7e562d7f318f1280dd22cf59a2550039838295a9
[simantics/platform.git] / bundles / org.simantics.help.core / src / org / simantics / help / core / HelpUtils.java
1 package org.simantics.help.core;
2
3 import java.io.IOException;
4 import java.io.StringWriter;
5 import java.net.URL;
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;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.TreeMap;
20
21 import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
22 import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
23 import org.eclipse.mylyn.wikitext.mediawiki.core.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;
41
42 import winterwell.markdown.pagemodel.MarkdownPage;
43
44 public class HelpUtils {
45
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);
53         return library;
54     }
55     
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);
63         return tutorialFile;
64     }
65
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();
75             
76             htmlHead(sb, graph.getRelatedValue2(tutorialFile, L0.HasName, Bindings.STRING));
77             sb.append(HelpUtils.markdownToHtml(graph, tutorialFile));
78             htmlHeadClose(sb);
79             
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());
84             try {
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) {
95                 e.printStackTrace();
96             }
97         }
98         return result;
99     }
100
101     private static void createDirsRec(Path path) throws IOException {
102         Path parent = path.getParent();
103         if (!Files.exists(parent)) {
104             createDirsRec(parent);
105         }
106         if (!Files.exists(path))
107             Files.createDirectory(path);
108     }
109
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);
120         }
121         return result;
122     }
123     
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);
133             try {
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) {
141                 e.printStackTrace();
142             }
143         }
144         return result;
145     }
146     
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");
154         sb.append("<hr>\n");
155     }
156     
157     private static void htmlHeadClose(StringBuilder sb) {
158         sb.append("</body></html>\n");
159     }
160
161     public static String createWidgetReference(ReadGraph graph, Resource indexRoot, String title) throws DatabaseException {
162
163         String ontologyDesc = NameUtils.getSafeLabel(graph, indexRoot);
164         
165         StringBuilder sb = new StringBuilder();
166         
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");
174         sb.append("<hr>\n");
175         sb.append("<h1 align=\"center\">" + title + "</h1>\n");
176         
177         Layer0 L0 = Layer0.getInstance(graph);
178         StructuralResource2 STR = StructuralResource2.getInstance(graph);
179         DocumentationResource DOC = DocumentationResource.getInstance(graph);
180         
181         List<Resource> types = ModelingUtils.searchByType(graph, indexRoot, DOC.DocumentComponentType);
182         for(Resource type : types) {
183
184             
185             String label = NameUtils.getSafeLabel(graph, type);
186
187             sb.append("<h2><a name=\"" + label + "\"></a>" + label + "</h2>\n");
188             sb.append("<h3>Description</h3>\n");
189
190             String desc = graph.getPossibleRelatedValue(type, L0.HasDescription);
191             if(desc == null) desc = "";
192             
193             sb.append("<p>" + WikiParser.parseToHtml(desc, false) + "</p>\n");
194             
195             sb.append("<h3>Base Types</h3>\n");
196             
197             Map<String,String> names = new HashMap<String,String>();
198
199             for(Resource r : graph.getSupertypes(type)) {
200
201                 if(graph.isInheritedFrom(r, STR.Component)) {
202                     
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;
210                     
211                     names.put(name, label2);
212
213                 }
214                 
215             }
216
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");
221             }
222
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");
232             
233             Map<String, Resource> propertyMap = new TreeMap<String, Resource>();
234             
235             for(Resource ass : graph.getObjects(type, L0.Asserts)) {
236                 
237                 Resource object = graph.getSingleObject(ass, L0.HasObject);
238                 
239                 if(graph.isInstanceOf(object, L0.SCLValue)) continue;
240                 if(graph.isInstanceOf(object, L0.Function)) continue;
241                 if(graph.isInstanceOf(object, L0.ExternalValue)) continue;
242
243                 Resource pred = graph.getSingleObject(ass, L0.HasPredicate);
244                 String pName = NameUtils.getSafeLabel(graph, pred);
245                 propertyMap.put(pName, ass);
246             }
247             
248             for (Entry<String, Resource> entry : propertyMap.entrySet()) {
249                 Resource ass = entry.getValue();
250                 Resource object = graph.getSingleObject(ass, L0.HasObject);
251                 
252                 Resource pred = graph.getSingleObject(ass, L0.HasPredicate);
253                 String pName = NameUtils.getSafeLabel(graph, pred);
254                 String valueType = graph.getPossibleRelatedValue(pred, L0.RequiresValueType);
255
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();
261                     if (!p1)
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);
275                 }
276
277                 String pDesc = graph.getPossibleRelatedValue(pred, L0.HasDescription);
278                 if(pDesc == null) pDesc = "";
279                 
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");
286             }
287
288             sb.append("  </tbody></table><br>\n");
289         }
290
291         sb.append("</body></html>\n");
292         return sb.toString();
293     }
294     
295     public static void clearHelpTocCache() {
296         SimanticsTocProvider.clearTocCache();
297     }
298     
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);
302     }
303     
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 : "";
308     }
309     
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);
314         return page.html();
315     }
316     
317     public static URL getHelpBrowserUrl() {
318         IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem();
319         URL url = helpSystem.resolve("", false);
320         return url;
321     }
322
323     private static class WikiParser {
324         
325         private static MarkupParser markupParser = new MarkupParser(new MediaWikiLanguage());
326         
327         private WikiParser() {}
328         
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();
335         }
336     }
337 }