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