All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.util.actions.CookieAction Maven / Gradle / Ivy

There is a newer version: RELEASE240
Show newest version
/*
 * 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.openide.util.actions;

import org.openide.nodes.Node;
import org.openide.nodes.NodeAdapter;
import org.openide.util.Lookup;
import org.openide.util.Mutex;

import java.beans.PropertyChangeEvent;

import java.lang.ref.*;

import java.util.*;


/** Not the preferred solution anymore, rather use
* Actions.context.
* To replace your action
* 
* layer definition use more delarative way:
* 
* <file name="action-pkg-ClassName.instance">
*   <attr name="type" stringvalue="org.netbeans.api.actions.Openable"/>
*   <attr name="delegate" methodvalue="org.openide.awt.Action.inject"/>
*   <attr name="selectionType" stringvalue="ANY"/>
*   <attr name="injectable" stringvalue="pkg.YourClass"/>
*   <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
*   <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
*   <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
* </file>
* 
* * @author Petr Hamernik, Jaroslav Tulach, Dafe Simonek, Jesse Glick */ public abstract class CookieAction extends NodeAction { /** name of property with cookies for this action */ private static final String PROP_COOKIES = "cookies"; // NOI18N /** Action will be enabled if there are one or more selected nodes * and there is exactly one node which supports the given cookies. */ public static final int MODE_ONE = 0x01; /** Action will be enabled if there are several selected nodes * and some of them (at least one, but not all) * support the given cookies. */ public static final int MODE_SOME = 0x02; /** Action will be enabled if there are one or more selected nodes * and all of them support the given cookies. */ public static final int MODE_ALL = 0x04; /** Action will be enabled if there is exactly one selected node * and it supports the given cookies. */ public static final int MODE_EXACTLY_ONE = 0x08; /** Action will be enabled if there are one or more selected nodes * and any of them (one, all, or some) support the given cookies. */ public static final int MODE_ANY = 0x07; // [PENDING] 0x06 should suffice, yes? --jglick private static final long serialVersionUID = 6031319415908298424L; private CookiesChangeListener listener = new CookiesChangeListener(this); /** Get the mode of the action: how strict it should be about * cookie support. * @return the mode of the action. Possible values are disjunctions of the MODE_XXX * constants. */ protected abstract int mode(); /** Get the cookies that this action requires. The cookies are disjunctive, i.e. a node * must support AT LEAST ONE of the cookies specified by this method. * * @return a list of cookies */ protected abstract Class[] cookieClasses(); // might not extend Node.Cookie; seems to work with Lookup /** Getter for cookies. * @return the set of cookies for this */ private Class[] getCookies() { Class[] ret = (Class[]) getProperty(PROP_COOKIES); if (ret != null) { return ret; } ret = cookieClasses(); putProperty(PROP_COOKIES, ret); return ret; } /** Test for enablement based on the cookies of selected nodes. * Generally subclasses should not override this except for strange * purposes, and then only calling the super method and adding a check. * Just use {@link #cookieClasses} and {@link #mode} to specify * the enablement logic. * @param activatedNodes the set of activated nodes * @return true to enable */ protected boolean enable(Node[] activatedNodes) { if (activatedNodes.length == 0) { return false; } // sets new nodes to cookie change listener listener.setNodes(activatedNodes); // perform enable / disable logic return doEnable(activatedNodes); } /** Implements ContextAwareAction interface method. */ public javax.swing.Action createContextAwareInstance(Lookup actionContext) { return new CookieDelegateAction(this, actionContext); } /** Helper, actually performs enable / disable logic */ boolean doEnable(Node[] activatedNodes) { int supported = resolveSupported(activatedNodes); if (supported == 0) { return false; } int mode = mode(); return // [PENDING] shouldn't MODE_ONE also say: && supported == 1? --jglick ((mode & MODE_ONE) != 0) || (((mode & MODE_ALL) != 0) && (supported == activatedNodes.length)) || (((mode & MODE_EXACTLY_ONE) != 0) && (activatedNodes.length == 1)) || (((mode & MODE_SOME) != 0) && (supported < activatedNodes.length)); } /** * Implementation of the above method. * * @param activatedNodes gives array of actually activated nodes. * @return number of supported classes */ private int resolveSupported(Node[] activatedNodes) { int ret = 0; Class[] cookies = getCookies(); for (Node n : activatedNodes) { for (Class cookie : cookies) { // test for supported cookies @SuppressWarnings("unchecked") Lookup.Template templ = new Lookup.Template(cookie); if (n.getLookup().lookupItem(templ) != null) { ret++; break; } } } return ret; } /** Tracks changes of cookie classes in currently selected nodes */ private static final class CookiesChangeListener extends NodeAdapter { /** our weak listener */ private org.openide.nodes.NodeListener listener; /** The nodes we are currently listening */ private volatile List> nodes; /** the associated action */ private Reference action; /** Constructor - asociates with given cookie action */ public CookiesChangeListener(CookieAction a) { listener = org.openide.nodes.NodeOp.weakNodeListener(this, null); action = new WeakReference(a); } /** Sets the nodes to work on */ void setNodes(Node[] newNodes) { // detach old nodes List> nodes2 = this.nodes; if (nodes2 != null) { detachListeners(nodes2); } nodes = null; // attach to new nodes if (newNodes != null) { List> tmp = new ArrayList>(newNodes.length); for (int i = 0; i < newNodes.length; i++) tmp.add(new WeakReference(newNodes[i])); attachListeners(tmp); this.nodes = tmp; } } /** Removes itself as a listener from given nodes */ void detachListeners(List> nodes) { if (nodes == null) { return; } Iterator> it = nodes.iterator(); while (it.hasNext()) { Node node = it.next().get(); if (node != null) { node.removeNodeListener(listener); } } } /** Attach itself as a listener to the given nodes */ void attachListeners(List> nodes) { Iterator> it = nodes.iterator(); while (it.hasNext()) { Node node = it.next().get(); if (node != null) { node.addNodeListener(listener); } } } /** Reacts to the cookie classes change - * calls enable on asociated action */ public void propertyChange(PropertyChangeEvent ev) { // filter only cookie classes changes if (!Node.PROP_COOKIE.equals(ev.getPropertyName())) { return; } // find asociated action final CookieAction a = action.get(); if (a == null) { return; } List> _nodes = this.nodes; if (_nodes != null) { ArrayList nonNullNodes = new ArrayList(_nodes.size()); Iterator> it = _nodes.iterator(); while (it.hasNext()) { Node node = it.next().get(); if (node != null) { nonNullNodes.add(node); } else { // If there is really a selection, it should not have been collected. return; } } final Node[] nodes2 = new Node[nonNullNodes.size()]; nonNullNodes.toArray(nodes2); Mutex.EVENT.writeAccess( new Runnable() { public void run() { a.setEnabled(a.enable(nodes2)); } } ); } } protected void finalize() { detachListeners(nodes); } } // end of CookiesChangeListener /** A delegate action that is usually associated with a specific lookup and * extract the nodes it operates on from it. Otherwise it delegates to the * regular NodeAction. */ static final class CookieDelegateAction extends org.openide.util.actions.NodeAction.DelegateAction implements org.openide.nodes.NodeListener, Runnable { /** our weak listener */ private org.openide.nodes.NodeListener listener; /** The nodes we are currently listening */ private List> nodes; public CookieDelegateAction(CookieAction a, Lookup actionContext) { super(a, actionContext); listener = org.openide.nodes.NodeOp.weakNodeListener(this, null); setNodes(nodes()); } public void resultChanged(org.openide.util.LookupEvent ev) { setNodes(nodes()); superResultChanged(ev); } private void superResultChanged(org.openide.util.LookupEvent ev) { super.resultChanged(ev); } public void childrenAdded(org.openide.nodes.NodeMemberEvent ev) { } public void childrenRemoved(org.openide.nodes.NodeMemberEvent ev) { } public void childrenReordered(org.openide.nodes.NodeReorderEvent ev) { } public void nodeDestroyed(org.openide.nodes.NodeEvent ev) { } public void propertyChange(PropertyChangeEvent ev) { // filter only cookie classes changes if (!Node.PROP_COOKIE.equals(ev.getPropertyName())) { return; } // find asociated action Mutex.EVENT.readAccess(this); } public void run() { superResultChanged(null); } /** Attach itself as a listener own nodes */ private void setNodes(org.openide.nodes.Node[] newNodes) { // detach listeners from old nodes detachListeners(nodes); // attach to new nodes if (newNodes != null) { nodes = new ArrayList>(newNodes.length); for (int i = 0; i < newNodes.length; i++) nodes.add(new WeakReference(newNodes[i])); } // attach listeners to new nodes attachListeners(nodes); } /** Removes itself as a listener from given nodes */ private void detachListeners(List> nodes) { if (nodes != null) { Iterator> it = nodes.iterator(); while (it.hasNext()) { Node node = it.next().get(); if (node != null) { node.removeNodeListener(listener); } } } } /** Attach itself as a listener to the given nodes */ private void attachListeners(List> nodes) { if (nodes != null) { Iterator> it = nodes.iterator(); while (it.hasNext()) { Node node = it.next().get(); if (node != null) { node.addNodeListener(listener); } } } } protected void finalize() { detachListeners(nodes); } } // end of CookieDelegateAction }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy