1 /* 2 * Copyright (c) 2008-2019 Emmanuel Dupuy. 3 * This project is distributed under the GPLv3 license. 4 * This is a Copyleft license that gives the user the right to use, 5 * copy and modify the code freely for non-commercial purposes. 6 */ 7 8 package org.jd.gui.view.component; 9 10 import org.fife.ui.rsyntaxtextarea.SyntaxConstants; 11 import org.jd.gui.api.API; 12 import org.jd.gui.api.feature.IndexesChangeListener; 13 import org.jd.gui.api.feature.UriGettable; 14 import org.jd.gui.api.model.Container; 15 import org.jd.gui.api.model.Indexes; 16 import org.jd.gui.util.exception.ExceptionUtil; 17 import org.jd.gui.util.index.IndexesUtil; 18 import org.jd.gui.util.io.TextReader; 19 import org.jd.gui.util.xml.AbstractXmlPathFinder; 20 21 import java.awt.*; 22 import java.net.URI; 23 import java.net.URISyntaxException; 24 import java.util.*; 25 import java.util.List; 26 import java.util.concurrent.Future; 27 28 public class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener { 29 protected API api; 30 protected Container.Entry entry; 31 protected Collection<Future<Indexes>> collectionOfFutureIndexes; 32 WebXmlFilePage(API api, Container.Entry entry)33 public WebXmlFilePage(API api, Container.Entry entry) { 34 this.api = api; 35 this.entry = entry; 36 // Load content file 37 String text = TextReader.getText(entry.getInputStream()); 38 // Create hyperlinks 39 new PathFinder().find(text); 40 // Display 41 setText(text); 42 } 43 getSyntaxStyle()44 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; } 45 isHyperlinkEnabled(HyperlinkData hyperlinkData)46 protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; } 47 openHyperlink(int x, int y, HyperlinkData hyperlinkData)48 protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) { 49 TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData; 50 51 if (data.enabled) { 52 try { 53 // Save current position in history 54 Point location = textArea.getLocationOnScreen(); 55 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y)); 56 URI uri = entry.getUri(); 57 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null)); 58 59 // Open link 60 if (hyperlinkData instanceof PathHyperlinkData) { 61 PathHyperlinkData d = (PathHyperlinkData)hyperlinkData; 62 String path = d.path; 63 Container.Entry entry = searchEntry(this.entry.getContainer().getRoot(), path); 64 if (entry != null) { 65 api.openURI(x, y, Collections.singletonList(entry), null, path); 66 } 67 } else { 68 String internalTypeName = data.internalTypeName; 69 List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName); 70 String rootUri = entry.getContainer().getRoot().getUri().toString(); 71 ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>(); 72 73 for (Container.Entry entry : entries) { 74 if (entry.getUri().toString().startsWith(rootUri)) { 75 sameContainerEntries.add(entry); 76 } 77 } 78 79 if (sameContainerEntries.size() > 0) { 80 api.openURI(x, y, sameContainerEntries, null, data.internalTypeName); 81 } else if (entries.size() > 0) { 82 api.openURI(x, y, entries, null, data.internalTypeName); 83 } 84 } 85 } catch (URISyntaxException e) { 86 assert ExceptionUtil.printStackTrace(e); 87 } 88 } 89 } 90 searchEntry(Container.Entry parent, String path)91 public static Container.Entry searchEntry(Container.Entry parent, String path) { 92 if (path.charAt(0) == '/') 93 path = path.substring(1); 94 return recursiveSearchEntry(parent, path); 95 } 96 recursiveSearchEntry(Container.Entry parent, String path)97 public static Container.Entry recursiveSearchEntry(Container.Entry parent, String path) { 98 Container.Entry entry = null; 99 100 for (Container.Entry child : parent.getChildren()) { 101 if (path.equals(child.getPath())) { 102 entry = child; 103 break; 104 } 105 } 106 107 if (entry != null) { 108 return entry; 109 } else { 110 for (Container.Entry child : parent.getChildren()) { 111 if (path.startsWith(child.getPath() + '/')) { 112 entry = child; 113 break; 114 } 115 } 116 117 return (entry != null) ? searchEntry(entry, path) : null; 118 } 119 } 120 121 // --- UriGettable --- // getUri()122 public URI getUri() { return entry.getUri(); } 123 124 // --- ContentSavable --- // getFileName()125 public String getFileName() { 126 String path = entry.getPath(); 127 int index = path.lastIndexOf('/'); 128 return path.substring(index+1); 129 } 130 131 // --- IndexesChangeListener --- // indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes)132 public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) { 133 // Update the list of containers 134 this.collectionOfFutureIndexes = collectionOfFutureIndexes; 135 // Refresh links 136 boolean refresh = false; 137 138 for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) { 139 TypeHyperlinkData data = (TypeHyperlinkData)entry.getValue(); 140 boolean enabled; 141 142 if (data instanceof PathHyperlinkData) { 143 PathHyperlinkData d = (PathHyperlinkData)data; 144 enabled = searchEntry(this.entry.getContainer().getRoot(), d.path) != null; 145 } else { 146 String internalTypeName = data.internalTypeName; 147 enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName); 148 } 149 150 if (data.enabled != enabled) { 151 data.enabled = enabled; 152 refresh = true; 153 } 154 } 155 156 if (refresh) { 157 textArea.repaint(); 158 } 159 } 160 161 public static class PathHyperlinkData extends TypeHyperlinkData { 162 public boolean enabled; 163 public String path; 164 PathHyperlinkData(int startPosition, int endPosition, String path)165 PathHyperlinkData(int startPosition, int endPosition, String path) { 166 super(startPosition, endPosition, null); 167 this.enabled = false; 168 this.path = path; 169 } 170 } 171 172 protected static List<String> typeHyperlinkPaths = Arrays.asList( 173 "web-app/filter/filter-class", 174 "web-app/listener/listener-class", 175 "web-app/servlet/servlet-class"); 176 177 protected static List<String> pathHyperlinkPaths = Arrays.asList( 178 "web-app/jsp-config/taglib/taglib-location", 179 "web-app/welcome-file-list/welcome-file", 180 "web-app/login-config/form-login-config/form-login-page", 181 "web-app/login-config/form-login-config/form-error-page", 182 "web-app/jsp-config/jsp-property-group/include-prelude", 183 "web-app/jsp-config/jsp-property-group/include-coda"); 184 185 protected static List<String> hyperlinkPaths = new ArrayList<>(typeHyperlinkPaths.size() + pathHyperlinkPaths.size()); 186 187 static { 188 hyperlinkPaths.addAll(typeHyperlinkPaths); 189 hyperlinkPaths.addAll(pathHyperlinkPaths); 190 } 191 192 public class PathFinder extends AbstractXmlPathFinder { PathFinder()193 public PathFinder() { 194 super(hyperlinkPaths); 195 } 196 handle(String path, String text, int position)197 public void handle(String path, String text, int position) { 198 String trim = text.trim(); 199 if (trim != null) { 200 int startIndex = position + text.indexOf(trim); 201 int endIndex = startIndex + trim.length(); 202 203 if (pathHyperlinkPaths.contains(path)) { 204 addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim)); 205 } else { 206 String internalTypeName = trim.replace('.', '/'); 207 addHyperlink(new TypeHyperlinkData(startIndex, endIndex, internalTypeName)); 208 } 209 } 210 } 211 } 212 } 213