/* * 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.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyEditor; import java.util.logging.Level; import java.util.logging.Logger; import net.neilcsmith.praxis.core.Argument; import net.neilcsmith.praxis.core.CallArguments; import net.neilcsmith.praxis.core.ControlAddress; import net.neilcsmith.praxis.core.info.ControlInfo; import net.neilcsmith.praxis.core.types.PString; import net.neilcsmith.praxis.gui.ControlBinding; import net.neilcsmith.praxis.live.core.api.Callback; import net.neilcsmith.praxis.live.properties.PraxisProperty; /** * * @author Neil C Smith (http://neilcsmith.net) */ public class BoundArgumentProperty extends PraxisProperty<Argument> { private final static Logger LOG = Logger.getLogger(BoundArgumentProperty.class.getName()); private final PropertyChangeSupport pcs; private final Adaptor adaptor; private final ControlAddress address; private final ControlInfo info; private final boolean writable; private final boolean isTransient; private final Argument defaultValue; private DelegatingArgumentEditor editor; private Argument value; BoundArgumentProperty(ControlAddress address, ControlInfo info) { super(Argument.class); if (address == null || info == null) { throw new NullPointerException(); } if (info.getOutputsInfo().length != 1) { throw new IllegalArgumentException("Property doesn't accept single argument"); } this.address = address; this.info = info; this.writable = isWritable(info); this.defaultValue = getDefault(info); this.isTransient = isTransient(info); pcs = new PropertyChangeSupport(this); adaptor = new Adaptor(); value = defaultValue; PXRHelper.getDefault().bind(address, adaptor); setName(address.getID()); setValue("canAutoComplete", Boolean.FALSE); } private boolean isWritable(ControlInfo info) { boolean rw; switch (info.getType()) { case Property: rw = true; break; case ReadOnlyProperty: rw = false; break; default: throw new IllegalArgumentException(); } return rw; } private Argument getDefault(ControlInfo info) { Argument[] defs = info.getDefaults(); Argument def = null; if (defs != null && defs.length > 0) { def = defs[0]; } if (def == null) { def = PString.EMPTY; } return def; } private boolean isTransient(ControlInfo info) { return info.getProperties().getBoolean(ControlInfo.KEY_TRANSIENT, false); } @Override protected Editor createEditor() { if (editor == null) { editor = new DelegatingArgumentEditor(this, info); } editor.setValue(value); return editor; } @Override public Argument getValue() { return value; } @Override public void setValue(Argument value) { if (!writable) { throw new UnsupportedOperationException("Read only property"); } if (this.value.equals(value)) { return; } setValueImpl(value, true, null); } public void setValue(Argument value, Callback callback) { setValueImpl(value, true, callback); } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } @Override public boolean supportsDefaultValue() { return true; } @Override public boolean isDefaultValue() { return Argument.equivalent(null, defaultValue, value); } @Override public void restoreDefaultValue() { if (editor != null) { editor.restoreDefaultEditor(); } setValue(defaultValue); } public boolean isTransient() { return isTransient; } @Override public String getHtmlDisplayName() { if (isTransient) { return "<i>" + getDisplayName() + "</i>"; } else { return null; } } public void setSyncing(boolean sync) { if (LOG.isLoggable(Level.FINE)) { if (sync) { LOG.log(Level.FINE, "Activating binding for : {0}", address); } else { LOG.log(Level.FINE, "Deactivating binding for : {0}", address); } } adaptor.setActive(sync); } public boolean isSyncing() { return adaptor.isActive(); } @Override public void dispose() { super.dispose(); PXRHelper.getDefault().unbind(adaptor); } Class<? extends Argument> getArgumentType() { return info.getOutputsInfo()[0].getType(); } ControlAddress getAddress() { return address; } ControlInfo getInfo() { return info; } private void setValueImpl(Argument value, boolean send, Callback callback) { if (value == null) { throw new NullPointerException(); } if (value instanceof SubCommandArgument) { LOG.finest("Delegating to Property Editor"); PropertyEditor ed = getPropertyEditor(); ed.setValue(value); value = (Argument) ed.getValue(); } Argument oldValue = this.value; if (send) { adaptor.sendValue(value, callback); } this.value = value; if (!Argument.equivalent(null, oldValue, value)) { pcs.firePropertyChange(address.getID(), oldValue, value); } } @Override public boolean canRead() { return true; } @Override public boolean canWrite() { return writable; } @Deprecated static BoundArgumentProperty create(ControlAddress address, ControlInfo info) { return new BoundArgumentProperty(address, info); } private class Adaptor extends ControlBinding.Adaptor { private Callback callback; private Adaptor() { setSyncRate(ControlBinding.SyncRate.Medium); // setActive(false); } @Override public void update() { Argument arg = null; ControlBinding binding = getBinding(); if (binding != null) { CallArguments args = binding.getArguments(); if (args.getSize() > 0) { arg = args.get(0); } } if (arg != null) { setValueImpl(arg, false, null); } } void sendValue(Argument val, Callback callback) { send(CallArguments.create(val)); if (callback != null) { if (this.callback != null) { this.callback.onError(CallArguments.EMPTY); } this.callback = callback; } } @Override public void onResponse(CallArguments args) { if (callback != null) { Callback cb = callback; callback = null; cb.onReturn(args); } } @Override public void onError(CallArguments args) { if (callback != null) { Callback cb = callback; callback = null; cb.onError(args); } } @Override public void updateBindingConfiguration() { // no op? } } }