/* * 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.awt.EventQueue; import java.awt.Image; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.Action; import net.neilcsmith.praxis.core.types.PBoolean; import net.neilcsmith.praxis.live.components.api.Components; import net.neilcsmith.praxis.live.properties.PraxisProperty; import net.neilcsmith.praxis.live.model.ComponentProxy; import net.neilcsmith.praxis.live.model.ProxyException; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.Exceptions; import org.openide.util.HelpCtx; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; /** * * @author Neil C Smith (http://neilcsmith.net) */ class PXRProxyNode extends AbstractNode { // private final static Logger LOG = Logger.getLogger(PXRProxyNode.class.getName()); private final PXRComponentProxy component; private Action[] actions; private Image icon; boolean ignore; PXRProxyNode(final PXRComponentProxy component) { this(component, component instanceof PXRContainerProxy ? new ContainerChildren((PXRContainerProxy) component) : Children.LEAF, new ProxyLookup(Lookups.singleton(component), component.getLookup())); } private PXRProxyNode(PXRComponentProxy component, Children children, Lookup lookup) { super(children, lookup); this.component = component; setName(component.getAddress().getID()); refreshProperties(); refreshActions(); } final void refreshProperties() { setSheet(createSheetOnEQ()); } final void refreshActions() { List<Action> lst = new ArrayList<>(); lst.add(component.getEditorAction()); List<Action> triggers = component.getTriggerActions(); if (!triggers.isEmpty()) { lst.add(null); lst.addAll(triggers); } List<Action> prop = component.getPropertyActions(); if (!prop.isEmpty()) { lst.add(null); lst.addAll(prop); } actions = lst.toArray(new Action[lst.size()]); } final void refreshChildren() { Children chs = getChildren(); assert chs instanceof ContainerChildren; if (chs instanceof ContainerChildren) { ((ContainerChildren) chs).update(); } } @Override public String getDisplayName() { return getName(); } @Override public Action[] getActions(boolean context) { return actions.clone(); } @Override public Action getPreferredAction() { return component.getEditorAction(); } @Override public boolean canDestroy() { return canDestroyImpl(); } private boolean canDestroyImpl() { // assert EventQueue.isDispatchThread(); return component.getParent() != null; } @Override public void destroy() throws IOException { if (EventQueue.isDispatchThread()) { destroyImpl(); } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { destroyImpl(); } }); } } private void destroyImpl() { assert EventQueue.isDispatchThread(); try { PXRContainerProxy container = component.getParent(); container.removeChild(container.getChildID(component), null); // component.dispose(); //@TODO should be done from container callback? } catch (ProxyException ex) { Exceptions.printStackTrace(ex); } } @Override public Image getIcon(int type) { if (icon == null) { icon = Components.getIcon(component.getType()); } return icon; } @Override public Image getOpenedIcon(int type) { return getIcon(type); } private Sheet createSheetOnEQ() { Sheet sheet = Sheet.createDefault(); Sheet.Set props = Sheet.createPropertiesSet(); sheet.put(props); for (PraxisProperty<?> proxyProp : component.getProxyProperties()) { proxyProp.setHidden(true); props.put(proxyProp); } for (String id : component.getPropertyIDs()) { Node.Property<?> prop = component.getProperty(id); if (prop.canWrite() && prop instanceof BoundArgumentProperty) { BoundArgumentProperty bap = (BoundArgumentProperty) prop; if (bap.getArgumentType() == PBoolean.class) { prop = new BooleanPropertyWrapper(bap); } } props.put(prop); } return sheet; } @Override public HelpCtx getHelpCtx() { return new HelpCtx(component.getType().toString()); } void propertyChange(String property, Object oldValue, Object newValue) { firePropertyChange(property, oldValue, newValue); } // class ComponentPropListener implements PropertyChangeListener { // // @Override // public void propertyChange(PropertyChangeEvent evt) { // String property = evt.getPropertyName(); //// if (!component.isProxiedProperty(property)) { // firePropertyChange(property, null, null); //// } // // } // // } static class ContainerChildren extends Children.Keys<String> { final PXRContainerProxy container; private ContainerChildren(PXRContainerProxy container) { this.container = container; setKeys(container.getChildIDs()); } @Override protected Node[] createNodes(String key) { ComponentProxy component = container.getChild(key); if (component != null) { return new Node[]{component.getNodeDelegate()}; } else { return new Node[0]; } } private void update() { setKeys(container.getChildIDs()); } } }