/* * 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.palette; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Comparator; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import net.neilcsmith.praxis.core.ComponentFactory; import net.neilcsmith.praxis.core.ComponentType; import net.neilcsmith.praxis.live.components.api.Components; import net.neilcsmith.praxis.live.core.api.DynamicFileSystem; import org.netbeans.spi.palette.PaletteController; import org.netbeans.spi.palette.PaletteFactory; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; import org.openide.filesystems.XMLFileSystem; import org.openide.loaders.DataFolder; import org.openide.nodes.Node; import org.openide.util.Exceptions; import org.xml.sax.SAXException; /** * * @author Neil C Smith <http://neilcsmith.net> */ public class ComponentPalette { private final static Logger LOG = Logger.getLogger(ComponentPalette.class.getName()); private final static String FOLDER = "PXR/Palette/"; private final static ComponentPalette INSTANCE = new ComponentPalette(); private final FileSystem memoryFS; private final FileSystem layer; private ComponentPalette() { memoryFS = FileUtil.createMemoryFileSystem(); layer = init(); if (layer != null) { DynamicFileSystem.getDefault().mount(layer); } } private FileSystem init() { TreeMap<String, TreeMap<ComponentType, ComponentFactory.MetaData<?>>> core = new TreeMap<>(); TreeMap<String, TreeMap<ComponentType, ComponentFactory.MetaData<?>>> others = new TreeMap<>(); buildMaps(core, others); StringBuilder sb = new StringBuilder(); buildLayerPrefix(sb); writeMap(sb, core, -100000); writeMap(sb, others, 100000); buildLayerSuffix(sb); LOG.log(Level.FINE, "Created ComponentPalette dynamic layer\n{0}", sb); FileObject memLayer = writeLayer(sb); if (memLayer != null) { try { return new XMLFileSystem(memLayer.toURL()); } catch (SAXException ex) { Exceptions.printStackTrace(ex); } } LOG.warning("Unable to create dynamic component palette"); return null; } private void buildMaps( TreeMap<String, TreeMap<ComponentType, ComponentFactory.MetaData<?>>> core, TreeMap<String, TreeMap<ComponentType, ComponentFactory.MetaData<?>>> others) { ComponentType[] types = Components.getComponentTypes(); for (ComponentType type : types) { String str = type.toString(); ComponentFactory.MetaData<?> data = Components.getMetaData(type); str = str.substring(0, str.lastIndexOf(':')); boolean cr = str.startsWith("core"); TreeMap<ComponentType, ComponentFactory.MetaData<?>> children = cr ? core.get(str) : others.get(str); if (children == null) { children = new TreeMap<>(TypeComparator.INSTANCE); if (cr) { core.put(str, children); } else { others.put(str, children); } } children.put(type, data); } } private void buildLayerPrefix(StringBuilder sb) { sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); sb.append("<!DOCTYPE filesystem PUBLIC \"-//NetBeans//DTD Filesystem 1.2//EN\" \"http://www.netbeans.org/dtds/filesystem-1_2.dtd\">\n"); sb.append("<filesystem>\n"); sb.append("<folder name=\"PXR\">\n"); sb.append("<folder name=\"Palette\">\n"); } private void writeMap(StringBuilder sb, TreeMap<String, TreeMap<ComponentType, ComponentFactory.MetaData<?>>> map, int position) { for (String category : map.keySet()) { startCategoryFolder(sb, category, position); for (ComponentType type : map.get(category).keySet()) { buildTypeFile(sb, type); } endCategoryFolder(sb); position += 10; } } private void startCategoryFolder(StringBuilder sb, String category, int position) { sb.append("<folder name=\"").append(safeFileName(category)).append("\">\n"); sb.append("<attr name=\"displayName\" stringvalue=\"") .append(category).append("\"/>\n"); sb.append("<attr name=\"position\" intvalue=\"") .append(position).append("\"/>\n"); } private void buildTypeFile(StringBuilder sb, ComponentType type) { sb.append("<file name=\"") .append(safeFileName(type.toString())) .append(".type\">\n"); sb.append("<attr name=\"displayName\" stringvalue=\"") .append(type.toString()).append("\"/>\n"); sb.append("<attr name=\"").append(TypeDataObject.TYPE_ATTR_KEY) .append("\" stringvalue=\"") .append(type).append("\"/>\n"); sb.append("</file>\n"); } private void endCategoryFolder(StringBuilder sb) { sb.append("</folder>\n"); } private void buildLayerSuffix(StringBuilder sb) { sb.append("</folder>\n"); // Palette sb.append("</folder>\n"); // PXR sb.append("</filesystem>"); } private String safeFileName(String fileName) { return fileName.replace(":", "__"); } private FileObject writeLayer(StringBuilder sb) { OutputStreamWriter writer = null; FileObject file = null; try { file = memoryFS.getRoot().createData("layer.xml"); writer = new OutputStreamWriter(file.getOutputStream(), "UTF-8"); writer.append(sb); } catch (Exception ex) { Exceptions.printStackTrace(ex); } finally { if (writer != null) { try { writer.close(); } catch (IOException ex) { Exceptions.printStackTrace(ex); } } } return file; } public PaletteController createPalette(String ... categories) { DataFolder paletteFolder = DataFolder.findFolder(FileUtil.getConfigFile(FOLDER)); Node rootNode = new PaletteFilterNode(paletteFolder.getNodeDelegate()); return PaletteFactory.createPalette(rootNode, new DefaultPaletteActions(), new DefaultPaletteFilter(categories.clone()), null); } public static ComponentPalette getDefault() { return INSTANCE; } private static class TypeComparator implements Comparator<ComponentType> { private final static TypeComparator INSTANCE = new TypeComparator(); private TypeComparator() { } @Override public int compare(ComponentType type1, ComponentType type2) { return type1.toString().compareTo(type2.toString()); } } }