blob: 25426d7a0882c0899c4ecc19acc0622e5c764706 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.spi.actions;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.Action;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.Mutex;
/**Inner stub action class which delegates to the parent action's methods.
* Used both for context aware instances, and for internal state for
* ContextAction instances
* @author Tim Boudreau
*/
class ActionStub<T> extends NbAction implements LookupListener, ContextAwareAction {
private final Lookup.Result<T> lkpResult;
private final Lookup context;
protected final ContextAction<T> parent;
protected boolean enabled;
ActionStub(Lookup context, ContextAction<T> parent) {
assert context != null;
this.context = context;
this.parent = parent;
lkpResult = context.lookupResult(parent.type);
lkpResult.addLookupListener(this);
if (getClass() == ActionStub.class) {
//avoid superclass call to Retained.collection() before
//it has initialized
enabled = isEnabled();
}
}
@Override
public Object getValue(String key) {
Object result = _getValue(key);
if (result == null) {
result = parent.getValue(key);
}
return result;
}
Object _getValue(String key) {
if (!attached()) {
//Make sure any code that updates the name runs - we are not
//listening to the lookup
resultChanged(null);
}
return pairs.get(key);
}
Collection<? extends T> collection() {
return lkpResult.allInstances();
}
public boolean isEnabled() {
Collection<? extends T> targets = collection();
assert targets != null;
assert parent != null;
return targets.isEmpty() ? false : parent.checkQuantity(targets) &&
parent.isEnabled(targets);
}
public void actionPerformed(ActionEvent e) {
assert isEnabled() : "Not enabled: " + this + " collection " +
collection() + " of " + parent.type.getName();
Collection<? extends T> targets = collection();
parent.actionPerformed(targets);
}
void enabledChanged(final boolean enabled) {
Mutex.EVENT.readAccess(new Runnable() {
public void run() {
firePropertyChange(PROP_ENABLED, !enabled, enabled); //NOI18N
if (ContextAction.unitTest) {
synchronized (parent) {
parent.notifyAll();
}
synchronized (this) {
this.notifyAll();
}
}
}
});
}
public void resultChanged(LookupEvent ev) {
if (ContextAction.unitTest) {
synchronized (parent) {
parent.notifyAll();
}
}
synchronized(parent.lock()) {
parent.change (collection(), this == parent.stub ? parent : this);
}
boolean old = enabled;
enabled = isEnabled();
if (old != enabled) {
enabledChanged(enabled);
}
}
@Override
public String toString() {
return super.toString() + "[name=" + getValue(NAME) + //NOI18N
"delegating={" + parent + "} context=" + //NOI18N
context + "]"; //NOI18N
}
@Override
protected NbAction internalCreateContextAwareInstance(Lookup actionContext) {
return parent.createStub(actionContext);
}
@Override
public boolean equals(Object o) {
return o != null && o.getClass() == getClass() && parent.equals(((ActionStub<?>) o).parent);
}
@Override
public int hashCode() {
return parent.hashCode() * 37;
}
}