/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2014 Neil C Smith. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 3 for more details. * * You should have received a copy of the GNU General Public License version 3 * along with this work; if not, see http://www.gnu.org/licenses/ * * * Please visit http://neilcsmith.net if you need additional information or * have any questions. */ package net.neilcsmith.praxis.live.pxr; import java.io.IOException; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.neilcsmith.praxis.core.ComponentAddress; import net.neilcsmith.praxis.live.model.Connection; import net.neilcsmith.praxis.live.properties.PraxisProperty; //import org.openide.util.RequestProcessor; /** * * @author Neil C Smith (http://neilcsmith.net) */ @SuppressWarnings("deprecation") class PXRWriter { private final static Logger LOG = Logger.getLogger(PXRWriter.class.getName()); final static String INDENT = " "; final static String AT = "@"; final static String CONNECT = "~"; private final PXRRootProxy root; private final PXRContainerProxy container; private final Set<String> children; private PXRWriter(PXRRootProxy root) { this.root = root; container = null; children = null; } private PXRWriter(PXRContainerProxy container, Set<String> children) { this.container = container; this.children = children; this.root = null; } private void doWrite(Appendable target) throws IOException { if (root != null) { // full graph writeComponent(target, root, 0); } else { // sub graph /// attributes? writeChildren(target, container, 0); writeConnections(target, container, 0); } } private void writeComponent(Appendable sb, PXRComponentProxy cmp, int level) throws IOException { LOG.finest("Writing component " + cmp.getAddress()); writeIndent(sb, level); sb.append(AT).append(' '); writeComponentID(sb, cmp); sb.append(' ').append(cmp.getType().toString()).append(" {\n"); if (cmp instanceof PXRRootProxy) { writeIndent(sb, level + 1); writeFormat(sb, 2); } writeAttributes(sb, cmp, level + 1); writeProperties(sb, cmp, level + 1); if (cmp instanceof PXRContainerProxy) { writeChildren(sb, (PXRContainerProxy) cmp, level + 1); writeConnections(sb, (PXRContainerProxy) cmp, level + 1); } writeIndent(sb, level); sb.append("}\n"); } private void writeComponentID(Appendable sb, PXRComponentProxy cmp) throws IOException { if (cmp instanceof PXRRootProxy) { sb.append(cmp.getAddress().toString()); } else { ComponentAddress ad = cmp.getAddress(); String id = ad.getComponentID(ad.getDepth() - 1); sb.append("./"); sb.append(id); } } private void writeAttributes(Appendable sb, PXRComponentProxy cmp, int level) throws IOException { String[] keys = cmp.getAttrKeys(); for (String key : keys) { writeIndent(sb, level); writeAttribute(sb, key, cmp.getAttr(key)); } } private void writeAttribute(Appendable sb, String key, String value) throws IOException { LOG.log(Level.FINEST, "Writing attribute {0} : {1}", new Object[]{key, value}); sb.append("#%").append(key).append(' '); sb.append(AttrUtils.escape(value)).append('\n'); } private void writeFormat(Appendable sb, int format) throws IOException { sb.append("#%").append(PXRParser.FORMAT_KEY).append(' '); sb.append(Integer.toString(format)).append('\n'); } private void writeProperties(Appendable sb, PXRComponentProxy cmp, int level) { String[] propIDs = cmp.getPropertyIDs(); for (String id : propIDs) { try { LOG.log(Level.FINEST, "Checking property {0}", id); BoundArgumentProperty prop = cmp.getProperty(id); if (!prop.canWrite()) { continue; } if (prop.supportsDefaultValue() && prop.isDefaultValue()) { continue; } if (prop.isTransient()) { LOG.log(Level.FINEST, "Property is transient {0}", id); continue; } LOG.log(Level.FINEST, "Writing property {0}", id); PraxisProperty.Editor editor = (PraxisProperty.Editor) prop.getPropertyEditor(); String code = editor.getPraxisInitializationString(); if (code == null || code.isEmpty()) { LOG.log(Level.FINEST, "No code returned from editor for {0}", id); continue; } writeIndent(sb, level); writeProperty(sb, id, code); } catch (Exception e) { // continue ??? LOG.log(Level.INFO, "Error writing property.", e); } } } private void writeProperty(Appendable sb, String id, String code) throws IOException { sb.append('.').append(id).append(' ').append(code).append('\n'); } private void writeChildren(Appendable sb, PXRContainerProxy container, int level) throws IOException { String[] childIDs = container.getChildIDs(); for (String id : childIDs) { if (level == 0 && children != null && !children.contains(id)) { LOG.log(Level.FINEST, "Skipping child : {0}", id); continue; } writeComponent(sb, container.getChild(id), level); } } private void writeConnections(Appendable sb, PXRContainerProxy container, int level) throws IOException { Connection[] connections = container.getConnections(); for (Connection connection : connections) { String c1 = connection.getChild1(); String c2 = connection.getChild2(); String p1 = connection.getPort1(); String p2 = connection.getPort2(); if (level == 0 && children != null && !(children.contains(c1) && children.contains(c2))) { LOG.log(Level.FINEST, "Skipping connection : {0}", connection); continue; } writeIndent(sb, level); writeConnection(sb, c1, p1, c2, p2); } } private void writeConnection(Appendable sb, String c1, String p1, String c2, String p2) throws IOException { sb.append(CONNECT).append(' '); sb.append("./").append(c1).append('!').append(p1).append(' '); sb.append("./").append(c2).append('!').append(p2).append('\n'); } private void writeIndent(Appendable sb, int level) throws IOException { for (int i = 0; i < level; i++) { sb.append(INDENT); } } static void write(PXRRootProxy root, Appendable target) throws IOException { new PXRWriter(root).doWrite(target); } static void writeSubGraph(PXRContainerProxy container, Set<String> children, Appendable target) throws IOException { if (children.isEmpty()) { return; } new PXRWriter(container, children).doWrite(target); } }