package org.simantics.help.core; import java.io.IOException; import java.io.StringWriter; import java.net.URL; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.eclipse.mylyn.wikitext.parser.MarkupParser; import org.eclipse.mylyn.wikitext.parser.builder.HtmlDocumentBuilder; import org.eclipse.mylyn.wikitext.mediawiki.MediaWikiLanguage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.help.IWorkbenchHelpSystem; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.BindingException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ManyObjectsForFunctionalRelationException; import org.simantics.db.exception.ServiceException; import org.simantics.document.base.ontology.DocumentationResource; import org.simantics.help.HelpResources; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingUtils; import org.simantics.structural.stubs.StructuralResource2; import winterwell.markdown.pagemodel.MarkdownPage; public class HelpUtils { public static Resource createHelpLibrary(WriteGraph graph, Resource parent) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); HelpResources HELP = HelpResources.getInstance(graph); Resource library = graph.newResource(); graph.claim(library, L0.InstanceOf, null, HELP.HelpLibrary); graph.addLiteral(library, L0.HasName, L0.NameOf, "Help Library", Bindings.STRING); graph.claim(parent, L0.ConsistsOf, L0.PartOf, library); return library; } public static Resource createHelpTutorial(WriteGraph graph, Resource parent, String name) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); HelpResources HELP = HelpResources.getInstance(graph); Resource tutorialFile = graph.newResource(); graph.claim(tutorialFile, L0.InstanceOf, null, HELP.TutorialFile); graph.addLiteral(tutorialFile, L0.HasName, L0.NameOf, name, Bindings.STRING); graph.claim(parent, L0.ConsistsOf, L0.PartOf, tutorialFile); return tutorialFile; } public static List collectHelps(ReadGraph graph, Resource indexRoot) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); HelpResources HELP = HelpResources.getInstance(graph); List tutorialFiles = ModelingUtils.searchByType(graph, indexRoot, HELP.TutorialFile); if (tutorialFiles.isEmpty()) return Collections.emptyList(); List result = new ArrayList<>(tutorialFiles.size()); for (Resource tutorialFile : tutorialFiles) { StringBuilder sb = new StringBuilder(); htmlHead(sb, graph.getRelatedValue2(tutorialFile, L0.HasName, Bindings.STRING)); sb.append(HelpUtils.markdownToHtml(graph, tutorialFile)); htmlHeadClose(sb); String indexRootURI = graph.getURI(indexRoot); String indexRootName = graph.getRelatedValue2(indexRoot, L0.HasName, Bindings.STRING); String tutorialFileURI = graph.getURI(tutorialFile); String suffix = tutorialFileURI.substring(indexRootURI.length()); try { if (suffix.startsWith("/")) suffix = suffix.substring(1); suffix = URLDecoder.decode(suffix, StandardCharsets.UTF_8.name()); Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve(suffix + ".html"); createDirsRec(outputPath.getParent()); if (!Files.exists(outputPath)) Files.createFile(outputPath); Files.write(outputPath, sb.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); result.add(outputPath); } catch (IOException e) { e.printStackTrace(); } } return result; } private static void createDirsRec(Path path) throws IOException { Path parent = path.getParent(); if (!Files.exists(parent)) { createDirsRec(parent); } if (!Files.exists(path)) Files.createDirectory(path); } public static Map> collectHelpsFromSharedLibraries(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Collection sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology)); if (sharedLibraries.isEmpty()) return Collections.emptyMap(); Map> result = new HashMap<>(sharedLibraries.size()); for (Resource library : sharedLibraries) { String libraryName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING); List paths = collectHelps(graph, library); result.put(libraryName, paths); } return result; } public static Map collectWidgetReferencesFromSharedLibraries(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Collection sharedLibraries = graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0.ConsistsOf, L0.SharedOntology)); if (sharedLibraries.isEmpty()) return Collections.emptyMap(); Map result = new HashMap<>(sharedLibraries.size()); for (Resource library : sharedLibraries) { String html = createWidgetReference(graph, library, "Widget Reference"); String indexRootName = graph.getRelatedValue2(library, L0.HasName, Bindings.STRING); try { Path outputPath = Activator.getHtmlDirectory().resolve(indexRootName).resolve("widgetReference.html"); createDirsRec(outputPath.getParent()); if (!Files.exists(outputPath)) Files.createFile(outputPath); Files.write(outputPath, html.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); result.put(indexRootName, outputPath); } catch (IOException e) { e.printStackTrace(); } } return result; } private static void htmlHead(StringBuilder sb, String title) { sb.append("\n"); sb.append("" + title + " Tutorial\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("

" + title + "

\n"); sb.append("
\n"); } private static void htmlHeadClose(StringBuilder sb) { sb.append("\n"); } public static String createWidgetReference(ReadGraph graph, Resource indexRoot, String title) throws DatabaseException { String ontologyDesc = NameUtils.getSafeLabel(graph, indexRoot); StringBuilder sb = new StringBuilder(); sb.append("\n"); sb.append("" + ontologyDesc+ " Widget Reference\n"); sb.append("\n"); sb.append("\n"); sb.append("\n"); sb.append("

" + ontologyDesc+ "

\n"); sb.append("

Widget Reference

\n"); sb.append("
\n"); sb.append("

" + title + "

\n"); Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); DocumentationResource DOC = DocumentationResource.getInstance(graph); List types = ModelingUtils.searchByType(graph, indexRoot, DOC.DocumentComponentType); for(Resource type : types) { String label = NameUtils.getSafeLabel(graph, type); sb.append("

" + label + "

\n"); sb.append("

Description

\n"); String desc = graph.getPossibleRelatedValue(type, L0.HasDescription); if(desc == null) desc = ""; sb.append("

" + WikiParser.parseToHtml(desc, false) + "

\n"); sb.append("

Base Types

\n"); Map names = new HashMap(); for(Resource r : graph.getSupertypes(type)) { if(graph.isInheritedFrom(r, STR.Component)) { String label2 = NameUtils.getSafeLabel(graph, r); String name = graph.getRelatedValue(r, L0.HasName); //if("Component".equals(name)) continue; if("Element".equals(name)) continue; if("DefinedElement".equals(name)) continue; if("PrimitiveComponent".equals(name)) continue; if("DocumentComponent".equals(name)) continue; names.put(name, label2); } } for(Map.Entry entry : names.entrySet()) { String stuff = "predefined/baseWidgets.html#"; sb.append("" + entry.getValue() + "\n"); //sb.append("" + entry.getValue() + "\n"); } sb.append("

Properties

\n"); sb.append("\n"); sb.append("\n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); Map propertyMap = new TreeMap(); for(Resource ass : graph.getObjects(type, L0.Asserts)) { Resource object = graph.getSingleObject(ass, L0.HasObject); if(graph.isInstanceOf(object, L0.SCLValue)) continue; if(graph.isInstanceOf(object, L0.Function)) continue; if(graph.isInstanceOf(object, L0.ExternalValue)) continue; Resource pred = graph.getSingleObject(ass, L0.HasPredicate); String pName = NameUtils.getSafeLabel(graph, pred); propertyMap.put(pName, ass); } for (Entry entry : propertyMap.entrySet()) { Resource ass = entry.getValue(); Resource object = graph.getSingleObject(ass, L0.HasObject); Resource pred = graph.getSingleObject(ass, L0.HasPredicate); String pName = NameUtils.getSafeLabel(graph, pred); String valueType = graph.getPossibleRelatedValue(pred, L0.RequiresValueType); Object jObject = graph.getValue(object); String objectName = jObject.toString(); if(jObject.getClass().isArray()) { Class c1 = jObject.getClass().getComponentType(); boolean p1 = c1.isPrimitive(); if (!p1) objectName = Arrays.toString((Object[])jObject); if (boolean.class.equals(c1)) objectName = Arrays.toString((boolean[])jObject); else if (byte.class.equals(c1)) objectName = Arrays.toString((byte[])jObject); else if (int.class.equals(c1)) objectName = Arrays.toString((int[])jObject); else if (long.class.equals(c1)) objectName = Arrays.toString((long[])jObject); else if (float.class.equals(c1)) objectName = Arrays.toString((float[])jObject); else if (double.class.equals(c1)) objectName = Arrays.toString((double[])jObject); } String pDesc = graph.getPossibleRelatedValue(pred, L0.HasDescription); if(pDesc == null) pDesc = ""; sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); sb.append(" \n"); } sb.append("

Property Name

Type

Default Value

Description
" + pName + "" + valueType + "" + objectName + "" + WikiParser.parseToHtml(pDesc, false) + "

\n"); } sb.append("\n"); return sb.toString(); } public static void clearHelpTocCache() { SimanticsTocProvider.clearTocCache(); } public static void saveHelpFileContents(WriteGraph graph, Resource helpFile, String currentText) throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException { HelpResources HELP = HelpResources.getInstance(graph); graph.claimLiteral(helpFile, HELP.HelpFile_contents, currentText, Bindings.STRING); } public static String readHelpFileContents(ReadGraph graph, Resource helpFile) throws DatabaseException { HelpResources HELP = HelpResources.getInstance(graph); String content = graph.getPossibleRelatedValue2(helpFile, HELP.HelpFile_contents, Bindings.STRING); return content != null ? content : ""; } public static String markdownToHtml(ReadGraph graph, Resource tutorialFile) throws DatabaseException { HelpResources HELP = HelpResources.getInstance(graph); String markdown = graph.getRelatedValue2(tutorialFile, HELP.HelpFile_contents, Bindings.STRING); MarkdownPage page = new MarkdownPage(markdown); return page.html(); } public static URL getHelpBrowserUrl() { IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem(); URL url = helpSystem.resolve("", false); return url; } private static class WikiParser { private static MarkupParser markupParser = new MarkupParser(new MediaWikiLanguage()); private WikiParser() {} public static String parseToHtml(String wiki, boolean asDocument) { StringWriter writer = new StringWriter(); HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer); markupParser.setBuilder(builder); markupParser.parse(wiki, asDocument); return writer.toString(); } } }