001package org.nasdanika.html.flow; 002 003import java.nio.charset.StandardCharsets; 004import java.security.MessageDigest; 005import java.util.List; 006import java.util.function.BiConsumer; 007import java.util.stream.Collectors; 008 009import org.apache.commons.codec.binary.Hex; 010import org.eclipse.emf.common.util.URI; 011import org.eclipse.emf.ecore.EObject; 012import org.eclipse.emf.ecore.ETypedElement; 013import org.eclipse.emf.ecore.util.EcoreUtil; 014import org.nasdanika.common.BiSupplier; 015import org.nasdanika.common.Context; 016import org.nasdanika.common.DiagramGenerator; 017import org.nasdanika.common.ProgressMonitor; 018import org.nasdanika.common.Util; 019import org.nasdanika.diagram.Diagram; 020import org.nasdanika.diagram.gen.Generator; 021import org.nasdanika.flow.FlowPackage; 022import org.nasdanika.flow.PackageElement; 023import org.nasdanika.html.emf.EObjectActionBuilder; 024import org.nasdanika.html.model.app.Action; 025import org.nasdanika.html.model.app.AppFactory; 026import org.nasdanika.html.model.app.SectionStyle; 027import org.nasdanika.html.model.bootstrap.BootstrapFactory; 028import org.nasdanika.html.model.bootstrap.Table; 029import org.nasdanika.html.model.bootstrap.TableCell; 030import org.nasdanika.html.model.bootstrap.TableRow; 031import org.nasdanika.html.model.bootstrap.TableSection; 032import org.nasdanika.ncore.util.NamedElementComparator; 033import org.nasdanika.ncore.util.NcoreUtil; 034 035public class PackageElementActionBuilder<T extends PackageElement<?>> extends EObjectActionBuilder<T> { 036 037 /** 038 * Descriptions shorter than this value are put on the top of the tabs, longer 039 * ones end up in their own tab. 040 */ 041 protected int descriptionTabLengthThreshold = 2500; 042 043 public PackageElementActionBuilder(T value, Context context) { 044 super(value, context); 045 } 046 047 @Override 048 protected Action buildAction( 049 Action action, 050 BiConsumer<EObject,Action> registry, 051 java.util.function.Consumer<org.nasdanika.common.Consumer<org.nasdanika.html.emf.EObjectActionResolver.Context>> resolveConsumer, 052 ProgressMonitor progressMonitor) throws Exception { 053 Action ret = super.buildAction(action, registry, resolveConsumer, progressMonitor); 054 T eObj = getTarget(); 055 URI uri = NcoreUtil.getUri(eObj); 056 String id = uri == null ? eObj.getUuid() : uri.toString(); 057 String digest = Hex.encodeHexString(MessageDigest.getInstance("SHA-256").digest(id.getBytes(StandardCharsets.UTF_8))); 058 ret.setId(digest); 059 060 String description = eObj.getDescription(); 061 addContent(ret, description); 062 ret.setDescription(description); 063 064 BiSupplier<EObject, String> cPath = NcoreUtil.containmentPath(eObj); 065 if (cPath == null || Util.isBlank(cPath.getSecond())) { 066 ret.setLocation("${base-uri}index.html"); 067 } else { 068 ret.setLocation(cPath.getSecond() + "/index.html"); 069 } 070 071 ret.setText(eObj.getName()); // Escape? 072 ret.setSectionStyle(SectionStyle.HEADER); 073 return ret; 074 } 075 076 @Override 077 public String name() { 078 return getTarget().getName(); 079 } 080 081 @Override 082 protected List<ETypedElement> getProperties() { 083 List<ETypedElement> propertiew = super.getProperties(); 084 propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__EXTENDS); 085 propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__EXTENSIONS); 086 propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__MODIFIERS); 087 return propertiew; 088 } 089 090 @Override 091 protected Table createPropertiesTable( 092 Action action, 093 org.nasdanika.html.emf.EObjectActionResolver.Context context, 094 ProgressMonitor progressMonitor) throws Exception { 095 Table propertiesTable = super.createPropertiesTable(action, context, progressMonitor); 096 propertiesTable.getAttributes().put("style", createText("width:auto")); 097 return propertiesTable; 098 } 099 100 @Override 101 protected void resolve( 102 Action action, 103 org.nasdanika.html.emf.EObjectActionResolver.Context context, 104 ProgressMonitor progressMonitor) throws Exception { 105 106 super.resolve(action, context, progressMonitor); 107 T semanticElement = getTarget(); 108 109 // Representations 110 for (Diagram representation: semanticElement.getRepresentations().values().stream().sorted(NamedElementComparator.INSTANCE).collect(Collectors.toList())) { 111 if (representation.getElements().isEmpty()) { 112 populateRepresentation(representation, action, context, progressMonitor); 113 } 114 Action representationAction; 115 if (Util.isBlank(representation.getName())) { 116 representationAction = action; 117 } else { 118 representationAction = AppFactory.eINSTANCE.createAction(); 119 representationAction.setText(representation.getName()); 120 action.getSections().add(representationAction); // TODO - support of navigation/navigation-modal - get from properties. 121 } 122 String rDescr = representation.getDescription(); 123 if (Util.isBlank(rDescr)) { 124 addContent(representationAction, createGenerator().generate(representation)); 125 } else { 126 Table table = BootstrapFactory.eINSTANCE.createTable(); 127 representationAction.getContent().add(table); 128 table.setBordered(true); 129 TableSection body = BootstrapFactory.eINSTANCE.createTableSection(); 130 table.setBody(body); 131 table.getAttributes().put("style", createText("width:auto")); 132 133 TableRow diagramRow = BootstrapFactory.eINSTANCE.createTableRow(); 134 body.getRows().add(diagramRow); 135 TableCell diagramCell = BootstrapFactory.eINSTANCE.createTableCell(); 136 diagramRow.getCells().add(diagramCell); 137 diagramCell.getContent().add(createText(createGenerator().generate(representation))); 138 139 TableRow descriptionRow = BootstrapFactory.eINSTANCE.createTableRow(); 140 body.getRows().add(descriptionRow); 141 TableCell descriptionCell = BootstrapFactory.eINSTANCE.createTableCell(); 142 descriptionRow.getCells().add(descriptionCell); 143 descriptionCell.getContent().add(createText(rDescr)); 144 } 145 } 146 147 // Adding documentation here so it appears under the properties table 148 action.getContent().addAll(EcoreUtil.copyAll(semanticElement.getDocumentation())); 149 } 150 151 /** 152 * Creates a diagram {@link Generator}. 153 * @return 154 */ 155 protected Generator createGenerator() { 156 return new Generator() { 157 158 @Override 159 protected DiagramGenerator getDiagramGenerator() { 160 return context == null ? super.getDiagramGenerator() : context.get(DiagramGenerator.class, super.getDiagramGenerator()); 161 } 162 163 }; 164 } 165 166 /** 167 * Populates empty representations. An empty representation indicates that it has to be auto-populated. 168 * Non-empty representations indicate that they were pre-populated, e.g. manually, and should not be auto-populated. 169 * @param representation 170 */ 171 protected void populateRepresentation( 172 Diagram representation, 173 Action action, 174 org.nasdanika.html.emf.EObjectActionResolver.Context context, 175 ProgressMonitor progressMonitor) throws Exception { 176 177 } 178 179}