org.netbeans.modules.javahelp.HelpCtxProcessor Maven / Gradle / Ivy
/*
* 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.modules.javahelp;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.beans.BeanInfo;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openide.loaders.DataObject;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.netbeans.api.javahelp.Help;
import org.openide.cookies.InstanceCookie;
import org.openide.loaders.Environment;
import org.openide.nodes.Node;
import org.openide.nodes.NodeEvent;
import org.openide.nodes.NodeListener;
import org.openide.nodes.NodeMemberEvent;
import org.openide.nodes.NodeReorderEvent;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.openide.xml.EntityCatalog;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
/** XML processor for help context links.
* The associated instance makes it suitable for
* inclusion in a menu or toolbar.
* @author Jesse Glick
*/
public final class HelpCtxProcessor implements Environment.Provider {
private static Help findHelp() {
return Lookup.getDefault().lookup(Help.class);
}
public @Override Lookup getEnvironment(final DataObject obj) {
try {
Class.forName("javax.help.HelpSet");
} catch (ClassNotFoundException ex) {
//JavaHelp not available, ignore:
return Lookup.EMPTY;
}
Installer.log.log(Level.FINE, "creating help context presenter from {0}", obj.getPrimaryFile());
return Lookups.singleton(new InstanceCookie() {
private Action instance = null;
public @Override String instanceName() {
return obj.getName();
}
public @Override Class> instanceClass() throws IOException, ClassNotFoundException {
return Action.class;
}
public @Override synchronized Object instanceCreate() throws IOException, ClassNotFoundException {
if (instance != null) {
return instance;
}
try {
Document doc = XMLUtil.parse(new InputSource(obj.getPrimaryFile().getURL().toString()), true, false, XMLUtil.defaultErrorHandler(), EntityCatalog.getDefault());
Element el = doc.getDocumentElement();
if (!el.getNodeName().equals("helpctx")) { // NOI18N
throw new IOException();
}
instance = new ShortcutAction(obj, el.getAttribute("id"), Boolean.valueOf(el.getAttribute("showmaster")));
if (obj.getPrimaryFile().getAttribute("iconBase") != null) { //NOI18N
instance.putValue("iconBase", obj.getPrimaryFile().getAttribute("iconBase")); //NOI18N
}
return instance;
} catch (IOException x) {
throw x;
} catch (Exception x) {
throw new IOException(x);
}
}
});
}
/** The presenter to be shown in a menu, e.g.
*/
private static final class ShortcutAction extends AbstractAction implements HelpCtx.Provider, NodeListener, ChangeListener {
private static final RequestProcessor RP =
new RequestProcessor(ShortcutAction.class);
/** associated XML file representing it
*/
private final DataObject obj;
/** the cached help context
*/
private String helpID;
/** cached flag to show the master help set
*/
private boolean showmaster;
/** Create a new presenter.
* @param obj XML file describing it
*/
public ShortcutAction(DataObject obj, String helpID, boolean showmaster) {
this.obj = obj;
this.helpID = helpID;
this.showmaster = showmaster;
putValue("noIconInMenu", true); // NOI18N
Installer.log.log(Level.FINE, "new ShortcutAction: {0} {1} showmaster={2}", new Object[] {obj, helpID, showmaster});
updateText();
updateIcon();
updateEnabled();
if (obj.isValid()) {
Node n = obj.getNodeDelegate();
n.addNodeListener(org.openide.nodes.NodeOp.weakNodeListener (this, n));
}
Help h = findHelp();
if (h != null) {
h.addChangeListener(WeakListeners.change(this, h));
}
}
/** Show the help.
* @param actionEvent ignored
*/
public @Override void actionPerformed(ActionEvent actionEvent) {
Help h = findHelp();
if (h != null) {
Installer.log.log(Level.FINE, "ShortcutAction.actionPerformed: {0} showmaster={1}", new Object[] {helpID, showmaster});
h.showHelp(new HelpCtx(helpID), showmaster);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
/**
* Help for the shortcut itself is generic.
* @return a neutral help context - welcome page
*/
public @Override HelpCtx getHelpCtx() {
// #23565:
return new HelpCtx("ide.welcome"); // NOI18N
}
/** Help sets may have changed.
* @param changeEvent ignore
*/
public @Override void stateChanged(ChangeEvent e) {
updateEnabled();
}
/** Called when the node delegate changes somehow,
* @param ev event indicating whether the change
* was of display name, icon, or other
*/
public @Override void propertyChange(PropertyChangeEvent ev) {
String prop = ev.getPropertyName();
if (!obj.isValid()) {
return;
}
if (prop == null || prop.equals(Node.PROP_NAME) || prop.equals(Node.PROP_DISPLAY_NAME)) {
updateText();
}
if (prop == null || prop.equals(Node.PROP_ICON)) {
updateIcon();
}
}
/** Update the text of the button according to node's
* display name. Handle mnemonics sanely.
*/
private void updateText() {
String text;
if (obj.isValid()) {
text = obj.getNodeDelegate().getDisplayName();
} else {
// #16364
text = "dead"; // NOI18N
}
putValue(Action.NAME, text);
}
/** Update the icon of the button according to the
* node delegate.
*/
private void updateIcon() {
if (obj.isValid()) {
Image icon = obj.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16);
if (icon != null) {
putValue(Action.SMALL_ICON, new ImageIcon(icon));
}
}
}
private void updateEnabled() {
RP.post(new Runnable() {
@Override
public void run() {
Help h = findHelp();
final Boolean valid = h == null
? Boolean.FALSE : h.isValidID(helpID, false);
if (valid != null) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setEnabled(valid.booleanValue());
}
});
}
Installer.log.log(Level.FINE,
"enabled: xml={0} id={1} enabled={2}", //NOI18N
new Object[]{obj.getPrimaryFile(), helpID, valid});
}
});
}
public @Override void nodeDestroyed(NodeEvent ev) {
setEnabled(false);
updateText();
}
public @Override void childrenAdded(NodeMemberEvent ev) {}
public @Override void childrenRemoved(NodeMemberEvent ev) {}
public @Override void childrenReordered(NodeReorderEvent ev) {}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy