1 package org.simantics.help.core;
\r
3 import java.io.IOException;
\r
4 import java.io.StringWriter;
\r
6 import java.net.URLDecoder;
\r
7 import java.nio.charset.StandardCharsets;
\r
8 import java.nio.file.Files;
\r
9 import java.nio.file.Path;
\r
10 import java.nio.file.StandardOpenOption;
\r
11 import java.util.ArrayList;
\r
12 import java.util.Arrays;
\r
13 import java.util.Collection;
\r
14 import java.util.Collections;
\r
15 import java.util.HashMap;
\r
16 import java.util.List;
\r
17 import java.util.Map;
\r
18 import java.util.Map.Entry;
\r
19 import java.util.TreeMap;
\r
21 import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
\r
22 import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
\r
23 import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
\r
24 import org.eclipse.ui.PlatformUI;
\r
25 import org.eclipse.ui.help.IWorkbenchHelpSystem;
\r
26 import org.simantics.databoard.Bindings;
\r
27 import org.simantics.db.ReadGraph;
\r
28 import org.simantics.db.Resource;
\r
29 import org.simantics.db.WriteGraph;
\r
30 import org.simantics.db.common.request.ObjectsWithType;
\r
31 import org.simantics.db.common.utils.NameUtils;
\r
32 import org.simantics.db.exception.BindingException;
\r
33 import org.simantics.db.exception.DatabaseException;
\r
34 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
\r
35 import org.simantics.db.exception.ServiceException;
\r
36 import org.simantics.document.base.ontology.DocumentationResource;
\r
37 import org.simantics.help.HelpResources;
\r
38 import org.simantics.layer0.Layer0;
\r
39 import org.simantics.modeling.ModelingUtils;
\r
40 import org.simantics.structural.stubs.StructuralResource2;
\r
42 import winterwell.markdown.pagemodel.MarkdownPage;
\r
44 public class HelpUtils {
\r
46 public static Resource createHelpLibrary(WriteGraph graph, Resource parent) throws DatabaseException {
\r
47 Layer0 L0 = Layer0.getInstance(graph);
\r
48 HelpResources HELP = HelpResources.getInstance(graph);
\r
49 Resource library = graph.newResource();
\r
50 graph.claim(library, L0.InstanceOf, null, HELP.HelpLibrary);
\r
51 graph.addLiteral(library, L0.HasName, L0.NameOf, "Help Library", Bindings.STRING);
\r
52 graph.claim(parent, L0.ConsistsOf, L0.PartOf, library);
\r
56 public static Resource createHelpTutorial(WriteGraph graph, Resource parent, String name) throws DatabaseException {
\r
57 Layer0 L0 = Layer0.getInstance(graph);
\r
58 HelpResources HELP = HelpResources.getInstance(graph);
\r
59 Resource tutorialFile = graph.newResource();
\r
60 graph.claim(tutorialFile, L0.InstanceOf, null, HELP.TutorialFile);
\r
61 graph.addLiteral(tutorialFile, L0.HasName, L0.NameOf, name, Bindings.STRING);
\r
62 graph.claim(parent, L0.ConsistsOf, L0.PartOf, tutorialFile);
\r
63 return tutorialFile;
\r
66 public static List<Path> collectHelps(ReadGraph graph, Resource indexRoot) throws DatabaseException {
\r
67 Layer0 L0 = Layer0.getInstance(graph);
\r
68 HelpResources HELP = HelpResources.getInstance(graph);
\r
69 List<Resource> tutorialFiles = ModelingUtils.searchByType(graph, indexRoot, HELP.TutorialFile);
\r
70 if (tutorialFiles.isEmpty())
\r
71 return Collections.emptyList();
\r
72 List<Path> result = new ArrayList<>(tutorialFiles.size());
\r
73 for (Resource tutorialFile : tutorialFiles) {
\r
74 StringBuilder sb = new StringBuilder();
\r
76 htmlHead(sb, graph.getRelatedValue2(tutorialFile, L0.HasName, Bindings.STRING));
\r
77 sb.append(HelpUtils.markdownToHtml(graph, tutorialFile));
\r
80 String indexRootURI = graph.getURI(indexRoot);
\r
81 String indexRootName = graph.getRelatedValue2(indexRoot, L0.HasName, Bindings.STRING);
\r
82 String tutorialFileURI = graph.getURI(tutorialFile);
\r
83 String suffix = tutorialFileURI.substring(indexRootURI.length());
\r
85 if (suffix.startsWith("/"))
\r
86 suffix = suffix.substring(1);
\r
87 suffix = URLDecoder.decode(suffix, StandardCharsets.UTF_8.name());
\r
88 Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve(suffix + ".html");
\r
89 createDirsRec(outputPath.getParent());
\r
90 if (!Files.exists(outputPath))
\r
91 Files.createFile(outputPath);
\r
92 Files.write(outputPath, sb.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
\r
93 result.add(outputPath);
\r
94 } catch (IOException e) {
\r
95 e.printStackTrace();
\r
101 private static void createDirsRec(Path path) throws IOException {
\r
102 Path parent = path.getParent();
\r
103 if (!Files.exists(parent)) {
\r
104 createDirsRec(parent);
\r
106 if (!Files.exists(path))
\r
107 Files.createDirectory(path);
\r
110 public static Map<String, List<Path>> collectHelpsFromSharedLibraries(ReadGraph graph) throws DatabaseException {
\r
111 Layer0 L0 = Layer0.getInstance(graph);
\r
112 Collection<Resource> sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology));
\r
113 if (sharedLibraries.isEmpty())
\r
114 return Collections.emptyMap();
\r
115 Map<String, List<Path>> result = new HashMap<>(sharedLibraries.size());
\r
116 for (Resource library : sharedLibraries) {
\r
117 String libraryName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING);
\r
118 List<Path> paths = collectHelps(graph, library);
\r
119 result.put(libraryName, paths);
\r
124 public static Map<String, Path> collectWidgetReferencesFromSharedLibraries(ReadGraph graph) throws DatabaseException {
\r
125 Layer0 L0 = Layer0.getInstance(graph);
\r
126 Collection<Resource> sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology));
\r
127 if (sharedLibraries.isEmpty())
\r
128 return Collections.emptyMap();
\r
129 Map<String, Path> result = new HashMap<>(sharedLibraries.size());
\r
130 for (Resource library : sharedLibraries) {
\r
131 String html = createWidgetReference(graph, library, "Widget Reference");
\r
132 String indexRootName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING);
\r
134 Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve("widgetReference.html");
\r
135 createDirsRec(outputPath.getParent());
\r
136 if (!Files.exists(outputPath))
\r
137 Files.createFile(outputPath);
\r
138 Files.write(outputPath, html.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
\r
139 result.put(indexRootName, outputPath);
\r
140 } catch (IOException e) {
\r
141 e.printStackTrace();
\r
147 private static void htmlHead(StringBuilder sb, String title) {
\r
148 sb.append("<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML//EN\">\n");
\r
149 sb.append("<html><head><title>" + title + " Tutorial</title>\n");
\r
150 sb.append("<link rel=\"Stylesheet\" type=\"text/css\" media=\"all\" href=\"../style.css\">\n");
\r
151 sb.append("</head>\n");
\r
152 sb.append("<body style=\"background-color: white;\">\n");
\r
153 sb.append("<h1 align=\"center\">" + title + "</h1>\n");
\r
154 sb.append("<hr>\n");
\r
157 private static void htmlHeadClose(StringBuilder sb) {
\r
158 sb.append("</body></html>\n");
\r
161 public static String createWidgetReference(ReadGraph graph, Resource indexRoot, String title) throws DatabaseException {
\r
163 String ontologyDesc = NameUtils.getSafeLabel(graph, indexRoot);
\r
165 StringBuilder sb = new StringBuilder();
\r
167 sb.append("<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML//EN\">\n");
\r
168 sb.append("<html><head><title>" + ontologyDesc+ " Widget Reference</title>\n");
\r
169 sb.append("<link rel=\"Stylesheet\" type=\"text/css\" media=\"all\" href=\"../style.css\">\n");
\r
170 sb.append("</head>\n");
\r
171 sb.append("<body style=\"background-color: white;\">\n");
\r
172 sb.append("<h1 align=\"center\">" + ontologyDesc+ "</h1>\n");
\r
173 sb.append("<h2 align=\"center\">Widget Reference</h2>\n");
\r
174 sb.append("<hr>\n");
\r
175 sb.append("<h1 align=\"center\">" + title + "</h1>\n");
\r
177 Layer0 L0 = Layer0.getInstance(graph);
\r
178 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
179 DocumentationResource DOC = DocumentationResource.getInstance(graph);
\r
181 List<Resource> types = ModelingUtils.searchByType(graph, indexRoot, DOC.DocumentComponentType);
\r
182 for(Resource type : types) {
\r
185 String label = NameUtils.getSafeLabel(graph, type);
\r
187 sb.append("<h2><a name=\"" + label + "\"></a>" + label + "</h2>\n");
\r
188 sb.append("<h3>Description</h3>\n");
\r
190 String desc = graph.getPossibleRelatedValue(type, L0.HasDescription);
\r
191 if(desc == null) desc = "";
\r
193 sb.append("<p>" + WikiParser.parseToHtml(desc, false) + "</p>\n");
\r
195 sb.append("<h3>Base Types</h3>\n");
\r
197 Map<String,String> names = new HashMap<String,String>();
\r
199 for(Resource r : graph.getSupertypes(type)) {
\r
201 if(graph.isInheritedFrom(r, STR.Component)) {
\r
203 String label2 = NameUtils.getSafeLabel(graph, r);
\r
204 String name = graph.getRelatedValue(r, L0.HasName);
\r
205 //if("Component".equals(name)) continue;
\r
206 if("Element".equals(name)) continue;
\r
207 if("DefinedElement".equals(name)) continue;
\r
208 if("PrimitiveComponent".equals(name)) continue;
\r
209 if("DocumentComponent".equals(name)) continue;
\r
211 names.put(name, label2);
\r
217 for(Map.Entry<String, String> entry : names.entrySet()) {
\r
218 String stuff = "predefined/baseWidgets.html#";
\r
219 sb.append("<a href=\"" + stuff + entry.getKey() + "\">" + entry.getValue() + "</a>\n");
\r
220 //sb.append("<a href=\"baseWidgets.html#" + entry.getKey() + "\">" + entry.getValue() + "</a>\n");
\r
223 sb.append("<h3>Properties</h3>\n");
\r
224 sb.append("<table style=\"width: 100%;\" border=\"1\" cellpadding=\"0\" cellspacing=\"0\">\n");
\r
225 sb.append("<tbody>\n");
\r
226 sb.append(" <tr style=\"background-color: silver;\">\n");
\r
227 sb.append(" <td valign=\"top\"><br><strong>Property Name</strong></td>\n");
\r
228 sb.append(" <td valign=\"top\"><br><strong>Type</strong></td>\n");
\r
229 sb.append(" <td valign=\"top\"><br><strong>Default Value</strong></td>\n");
\r
230 sb.append(" <td valign=\"top\"><br><strong>Description</strong></td>\n");
\r
231 sb.append(" </tr>\n");
\r
233 Map<String, Resource> propertyMap = new TreeMap<String, Resource>();
\r
235 for(Resource ass : graph.getObjects(type, L0.Asserts)) {
\r
237 Resource object = graph.getSingleObject(ass, L0.HasObject);
\r
239 if(graph.isInstanceOf(object, L0.SCLValue)) continue;
\r
240 if(graph.isInstanceOf(object, L0.Function)) continue;
\r
241 if(graph.isInstanceOf(object, L0.ExternalValue)) continue;
\r
243 Resource pred = graph.getSingleObject(ass, L0.HasPredicate);
\r
244 String pName = NameUtils.getSafeLabel(graph, pred);
\r
245 propertyMap.put(pName, ass);
\r
248 for (Entry<String, Resource> entry : propertyMap.entrySet()) {
\r
249 Resource ass = entry.getValue();
\r
250 Resource object = graph.getSingleObject(ass, L0.HasObject);
\r
252 Resource pred = graph.getSingleObject(ass, L0.HasPredicate);
\r
253 String pName = NameUtils.getSafeLabel(graph, pred);
\r
254 String valueType = graph.getPossibleRelatedValue(pred, L0.RequiresValueType);
\r
256 Object jObject = graph.getValue(object);
\r
257 String objectName = jObject.toString();
\r
258 if(jObject.getClass().isArray()) {
\r
259 Class<?> c1 = jObject.getClass().getComponentType();
\r
260 boolean p1 = c1.isPrimitive();
\r
262 objectName = Arrays.toString((Object[])jObject);
\r
263 if (boolean.class.equals(c1))
\r
264 objectName = Arrays.toString((boolean[])jObject);
\r
265 else if (byte.class.equals(c1))
\r
266 objectName = Arrays.toString((byte[])jObject);
\r
267 else if (int.class.equals(c1))
\r
268 objectName = Arrays.toString((int[])jObject);
\r
269 else if (long.class.equals(c1))
\r
270 objectName = Arrays.toString((long[])jObject);
\r
271 else if (float.class.equals(c1))
\r
272 objectName = Arrays.toString((float[])jObject);
\r
273 else if (double.class.equals(c1))
\r
274 objectName = Arrays.toString((double[])jObject);
\r
277 String pDesc = graph.getPossibleRelatedValue(pred, L0.HasDescription);
\r
278 if(pDesc == null) pDesc = "";
\r
280 sb.append(" <tr>\n");
\r
281 sb.append(" <td valign=\"top\">" + pName + "</td>\n");
\r
282 sb.append(" <td valign=\"top\">" + valueType + "</td>\n");
\r
283 sb.append(" <td valign=\"top\">" + objectName + "</td>\n");
\r
284 sb.append(" <td valign=\"top\">" + WikiParser.parseToHtml(pDesc, false) + "</td>\n");
\r
285 sb.append(" </tr>\n");
\r
288 sb.append(" </tbody></table><br>\n");
\r
291 sb.append("</body></html>\n");
\r
292 return sb.toString();
\r
295 public static void clearHelpTocCache() {
\r
296 SimanticsTocProvider.clearTocCache();
\r
299 public static void saveHelpFileContents(WriteGraph graph, Resource helpFile, String currentText) throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
\r
300 HelpResources HELP = HelpResources.getInstance(graph);
\r
301 graph.claimLiteral(helpFile, HELP.HelpFile_contents, currentText, Bindings.STRING);
\r
304 public static String readHelpFileContents(ReadGraph graph, Resource helpFile) throws DatabaseException {
\r
305 HelpResources HELP = HelpResources.getInstance(graph);
\r
306 String content = graph.getPossibleRelatedValue2(helpFile, HELP.HelpFile_contents, Bindings.STRING);
\r
307 return content != null ? content : "";
\r
310 public static String markdownToHtml(ReadGraph graph, Resource tutorialFile) throws DatabaseException {
\r
311 HelpResources HELP = HelpResources.getInstance(graph);
\r
312 String markdown = graph.getRelatedValue2(tutorialFile, HELP.HelpFile_contents, Bindings.STRING);
\r
313 MarkdownPage page = new MarkdownPage(markdown);
\r
314 return page.html();
\r
317 public static URL getHelpBrowserUrl() {
\r
318 IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem();
\r
319 URL url = helpSystem.resolve("", false);
\r
323 private static class WikiParser {
\r
325 private static MarkupParser markupParser = new MarkupParser(new MediaWikiLanguage());
\r
327 private WikiParser() {}
\r
329 public static String parseToHtml(String wiki, boolean asDocument) {
\r
330 StringWriter writer = new StringWriter();
\r
331 HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer);
\r
332 markupParser.setBuilder(builder);
\r
333 markupParser.parse(wiki, asDocument);
\r
334 return writer.toString();
\r