+package org.simantics.help.core;\r
+\r
+import java.io.IOException;\r
+import java.io.StringWriter;\r
+import java.net.URL;\r
+import java.net.URLDecoder;\r
+import java.nio.charset.StandardCharsets;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.StandardOpenOption;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.TreeMap;\r
+\r
+import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;\r
+import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;\r
+import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.help.IWorkbenchHelpSystem;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ObjectsWithType;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.BindingException;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.document.base.ontology.DocumentationResource;\r
+import org.simantics.help.HelpResources;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingUtils;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+\r
+import winterwell.markdown.pagemodel.MarkdownPage;\r
+\r
+public class HelpUtils {\r
+\r
+ public static Resource createHelpLibrary(WriteGraph graph, Resource parent) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ Resource library = graph.newResource();\r
+ graph.claim(library, L0.InstanceOf, null, HELP.HelpLibrary);\r
+ graph.addLiteral(library, L0.HasName, L0.NameOf, "Help Library", Bindings.STRING);\r
+ graph.claim(parent, L0.ConsistsOf, L0.PartOf, library);\r
+ return library;\r
+ }\r
+ \r
+ public static Resource createHelpTutorial(WriteGraph graph, Resource parent, String name) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ Resource tutorialFile = graph.newResource();\r
+ graph.claim(tutorialFile, L0.InstanceOf, null, HELP.TutorialFile);\r
+ graph.addLiteral(tutorialFile, L0.HasName, L0.NameOf, name, Bindings.STRING);\r
+ graph.claim(parent, L0.ConsistsOf, L0.PartOf, tutorialFile);\r
+ return tutorialFile;\r
+ }\r
+\r
+ public static List<Path> collectHelps(ReadGraph graph, Resource indexRoot) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ List<Resource> tutorialFiles = ModelingUtils.searchByType(graph, indexRoot, HELP.TutorialFile);\r
+ if (tutorialFiles.isEmpty())\r
+ return Collections.emptyList();\r
+ List<Path> result = new ArrayList<>(tutorialFiles.size());\r
+ for (Resource tutorialFile : tutorialFiles) {\r
+ StringBuilder sb = new StringBuilder();\r
+ \r
+ htmlHead(sb, graph.getRelatedValue2(tutorialFile, L0.HasName, Bindings.STRING));\r
+ sb.append(HelpUtils.markdownToHtml(graph, tutorialFile));\r
+ htmlHeadClose(sb);\r
+ \r
+ String indexRootURI = graph.getURI(indexRoot);\r
+ String indexRootName = graph.getRelatedValue2(indexRoot, L0.HasName, Bindings.STRING);\r
+ String tutorialFileURI = graph.getURI(tutorialFile);\r
+ String suffix = tutorialFileURI.substring(indexRootURI.length());\r
+ try {\r
+ if (suffix.startsWith("/"))\r
+ suffix = suffix.substring(1);\r
+ suffix = URLDecoder.decode(suffix, StandardCharsets.UTF_8.name());\r
+ Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve(suffix + ".html");\r
+ createDirsRec(outputPath.getParent());\r
+ if (!Files.exists(outputPath))\r
+ Files.createFile(outputPath);\r
+ Files.write(outputPath, sb.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);\r
+ result.add(outputPath);\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private static void createDirsRec(Path path) throws IOException {\r
+ Path parent = path.getParent();\r
+ if (!Files.exists(parent)) {\r
+ createDirsRec(parent);\r
+ }\r
+ if (!Files.exists(path))\r
+ Files.createDirectory(path);\r
+ }\r
+\r
+ public static Map<String, List<Path>> collectHelpsFromSharedLibraries(ReadGraph graph) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Collection<Resource> sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology));\r
+ if (sharedLibraries.isEmpty())\r
+ return Collections.emptyMap();\r
+ Map<String, List<Path>> result = new HashMap<>(sharedLibraries.size());\r
+ for (Resource library : sharedLibraries) {\r
+ String libraryName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING);\r
+ List<Path> paths = collectHelps(graph, library);\r
+ result.put(libraryName, paths);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ public static Map<String, Path> collectWidgetReferencesFromSharedLibraries(ReadGraph graph) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Collection<Resource> sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology));\r
+ if (sharedLibraries.isEmpty())\r
+ return Collections.emptyMap();\r
+ Map<String, Path> result = new HashMap<>(sharedLibraries.size());\r
+ for (Resource library : sharedLibraries) {\r
+ String html = createWidgetReference(graph, library, "Widget Reference");\r
+ String indexRootName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING);\r
+ try {\r
+ Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve("widgetReference.html");\r
+ createDirsRec(outputPath.getParent());\r
+ if (!Files.exists(outputPath))\r
+ Files.createFile(outputPath);\r
+ Files.write(outputPath, html.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);\r
+ result.put(indexRootName, outputPath);\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ private static void htmlHead(StringBuilder sb, String title) {\r
+ sb.append("<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML//EN\">\n");\r
+ sb.append("<html><head><title>" + title + " Tutorial</title>\n");\r
+ sb.append("<link rel=\"Stylesheet\" type=\"text/css\" media=\"all\" href=\"../style.css\">\n");\r
+ sb.append("</head>\n");\r
+ sb.append("<body style=\"background-color: white;\">\n");\r
+ sb.append("<h1 align=\"center\">" + title + "</h1>\n");\r
+ sb.append("<hr>\n");\r
+ }\r
+ \r
+ private static void htmlHeadClose(StringBuilder sb) {\r
+ sb.append("</body></html>\n");\r
+ }\r
+\r
+ public static String createWidgetReference(ReadGraph graph, Resource indexRoot, String title) throws DatabaseException {\r
+\r
+ String ontologyDesc = NameUtils.getSafeLabel(graph, indexRoot);\r
+ \r
+ StringBuilder sb = new StringBuilder();\r
+ \r
+ sb.append("<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML//EN\">\n");\r
+ sb.append("<html><head><title>" + ontologyDesc+ " Widget Reference</title>\n");\r
+ sb.append("<link rel=\"Stylesheet\" type=\"text/css\" media=\"all\" href=\"../style.css\">\n");\r
+ sb.append("</head>\n");\r
+ sb.append("<body style=\"background-color: white;\">\n");\r
+ sb.append("<h1 align=\"center\">" + ontologyDesc+ "</h1>\n");\r
+ sb.append("<h2 align=\"center\">Widget Reference</h2>\n");\r
+ sb.append("<hr>\n");\r
+ sb.append("<h1 align=\"center\">" + title + "</h1>\n");\r
+ \r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+ DocumentationResource DOC = DocumentationResource.getInstance(graph);\r
+ \r
+ List<Resource> types = ModelingUtils.searchByType(graph, indexRoot, DOC.DocumentComponentType);\r
+ for(Resource type : types) {\r
+\r
+ \r
+ String label = NameUtils.getSafeLabel(graph, type);\r
+\r
+ sb.append("<h2><a name=\"" + label + "\"></a>" + label + "</h2>\n");\r
+ sb.append("<h3>Description</h3>\n");\r
+\r
+ String desc = graph.getPossibleRelatedValue(type, L0.HasDescription);\r
+ if(desc == null) desc = "";\r
+ \r
+ sb.append("<p>" + WikiParser.parseToHtml(desc, false) + "</p>\n");\r
+ \r
+ sb.append("<h3>Base Types</h3>\n");\r
+ \r
+ Map<String,String> names = new HashMap<String,String>();\r
+\r
+ for(Resource r : graph.getSupertypes(type)) {\r
+\r
+ if(graph.isInheritedFrom(r, STR.Component)) {\r
+ \r
+ String label2 = NameUtils.getSafeLabel(graph, r);\r
+ String name = graph.getRelatedValue(r, L0.HasName);\r
+ //if("Component".equals(name)) continue;\r
+ if("Element".equals(name)) continue;\r
+ if("DefinedElement".equals(name)) continue;\r
+ if("PrimitiveComponent".equals(name)) continue;\r
+ if("DocumentComponent".equals(name)) continue;\r
+ \r
+ names.put(name, label2);\r
+\r
+ }\r
+ \r
+ }\r
+\r
+ for(Map.Entry<String, String> entry : names.entrySet()) {\r
+ String stuff = "predefined/baseWidgets.html#";\r
+ sb.append("<a href=\"" + stuff + entry.getKey() + "\">" + entry.getValue() + "</a>\n");\r
+ //sb.append("<a href=\"baseWidgets.html#" + entry.getKey() + "\">" + entry.getValue() + "</a>\n");\r
+ }\r
+\r
+ sb.append("<h3>Properties</h3>\n");\r
+ sb.append("<table style=\"width: 100%;\" border=\"1\" cellpadding=\"0\" cellspacing=\"0\">\n");\r
+ sb.append("<tbody>\n");\r
+ sb.append(" <tr style=\"background-color: silver;\">\n");\r
+ sb.append(" <td valign=\"top\"><br><strong>Property Name</strong></td>\n");\r
+ sb.append(" <td valign=\"top\"><br><strong>Type</strong></td>\n");\r
+ sb.append(" <td valign=\"top\"><br><strong>Default Value</strong></td>\n");\r
+ sb.append(" <td valign=\"top\"><br><strong>Description</strong></td>\n");\r
+ sb.append(" </tr>\n");\r
+ \r
+ Map<String, Resource> propertyMap = new TreeMap<String, Resource>();\r
+ \r
+ for(Resource ass : graph.getObjects(type, L0.Asserts)) {\r
+ \r
+ Resource object = graph.getSingleObject(ass, L0.HasObject);\r
+ \r
+ if(graph.isInstanceOf(object, L0.SCLValue)) continue;\r
+ if(graph.isInstanceOf(object, L0.Function)) continue;\r
+ if(graph.isInstanceOf(object, L0.ExternalValue)) continue;\r
+\r
+ Resource pred = graph.getSingleObject(ass, L0.HasPredicate);\r
+ String pName = NameUtils.getSafeLabel(graph, pred);\r
+ propertyMap.put(pName, ass);\r
+ }\r
+ \r
+ for (Entry<String, Resource> entry : propertyMap.entrySet()) {\r
+ Resource ass = entry.getValue();\r
+ Resource object = graph.getSingleObject(ass, L0.HasObject);\r
+ \r
+ Resource pred = graph.getSingleObject(ass, L0.HasPredicate);\r
+ String pName = NameUtils.getSafeLabel(graph, pred);\r
+ String valueType = graph.getPossibleRelatedValue(pred, L0.RequiresValueType);\r
+\r
+ Object jObject = graph.getValue(object);\r
+ String objectName = jObject.toString();\r
+ if(jObject.getClass().isArray()) {\r
+ Class<?> c1 = jObject.getClass().getComponentType();\r
+ boolean p1 = c1.isPrimitive();\r
+ if (!p1)\r
+ objectName = Arrays.toString((Object[])jObject);\r
+ if (boolean.class.equals(c1))\r
+ objectName = Arrays.toString((boolean[])jObject);\r
+ else if (byte.class.equals(c1))\r
+ objectName = Arrays.toString((byte[])jObject);\r
+ else if (int.class.equals(c1))\r
+ objectName = Arrays.toString((int[])jObject);\r
+ else if (long.class.equals(c1))\r
+ objectName = Arrays.toString((long[])jObject);\r
+ else if (float.class.equals(c1))\r
+ objectName = Arrays.toString((float[])jObject);\r
+ else if (double.class.equals(c1))\r
+ objectName = Arrays.toString((double[])jObject);\r
+ }\r
+\r
+ String pDesc = graph.getPossibleRelatedValue(pred, L0.HasDescription);\r
+ if(pDesc == null) pDesc = "";\r
+ \r
+ sb.append(" <tr>\n");\r
+ sb.append(" <td valign=\"top\">" + pName + "</td>\n");\r
+ sb.append(" <td valign=\"top\">" + valueType + "</td>\n");\r
+ sb.append(" <td valign=\"top\">" + objectName + "</td>\n");\r
+ sb.append(" <td valign=\"top\">" + WikiParser.parseToHtml(pDesc, false) + "</td>\n");\r
+ sb.append(" </tr>\n");\r
+ }\r
+\r
+ sb.append(" </tbody></table><br>\n");\r
+ }\r
+\r
+ sb.append("</body></html>\n");\r
+ return sb.toString();\r
+ }\r
+ \r
+ public static void clearHelpTocCache() {\r
+ SimanticsTocProvider.clearTocCache();\r
+ }\r
+ \r
+ public static void saveHelpFileContents(WriteGraph graph, Resource helpFile, String currentText) throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException {\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ graph.claimLiteral(helpFile, HELP.HelpFile_contents, currentText, Bindings.STRING);\r
+ }\r
+ \r
+ public static String readHelpFileContents(ReadGraph graph, Resource helpFile) throws DatabaseException {\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ String content = graph.getPossibleRelatedValue2(helpFile, HELP.HelpFile_contents, Bindings.STRING);\r
+ return content != null ? content : "";\r
+ }\r
+ \r
+ public static String markdownToHtml(ReadGraph graph, Resource tutorialFile) throws DatabaseException {\r
+ HelpResources HELP = HelpResources.getInstance(graph);\r
+ String markdown = graph.getRelatedValue2(tutorialFile, HELP.HelpFile_contents, Bindings.STRING);\r
+ MarkdownPage page = new MarkdownPage(markdown);\r
+ return page.html();\r
+ }\r
+ \r
+ public static URL getHelpBrowserUrl() {\r
+ IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem();\r
+ URL url = helpSystem.resolve("", false);\r
+ return url;\r
+ }\r
+\r
+ private static class WikiParser {\r
+ \r
+ private static MarkupParser markupParser = new MarkupParser(new MediaWikiLanguage());\r
+ \r
+ private WikiParser() {}\r
+ \r
+ public static String parseToHtml(String wiki, boolean asDocument) {\r
+ StringWriter writer = new StringWriter();\r
+ HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer);\r
+ markupParser.setBuilder(builder);\r
+ markupParser.parse(wiki, asDocument);\r
+ return writer.toString();\r
+ }\r
+ }\r
+}\r