blob: 64c4a1f39ed848f69f6abb9d509edd1a435a719a [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.modules.xml.catalog;
import java.awt.Image;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Action;
import org.netbeans.modules.xml.catalog.settings.CatalogSettings;
import org.netbeans.modules.xml.catalog.spi.CatalogDescriptor;
import org.netbeans.modules.xml.catalog.spi.CatalogDescriptor2;
import org.netbeans.modules.xml.catalog.spi.CatalogDescriptorBase;
import org.netbeans.modules.xml.catalog.spi.CatalogListener;
import org.netbeans.modules.xml.catalog.spi.CatalogReader;
import org.netbeans.modules.xml.catalog.spi.CatalogWriter;
import org.openide.actions.PropertiesAction;
import org.openide.nodes.BeanNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.actions.NodeAction;
import org.openide.util.actions.SystemAction;
/**
* Node representing a catalog.
* Every catalog reader is considered to be a bean.
* Information about catalog instance are obtained using CatalogDescriptorBase interface
* if passed instance implements it.
*
* @author Petr Kuzel
* @version 1.0
*/
final class CatalogNode extends BeanNode implements Refreshable, PropertyChangeListener, Node.Cookie {
private CatalogReader catalog;
/** Creates new CatalogNode */
public CatalogNode(CatalogReader catalog) throws IntrospectionException {
super(catalog, new CatalogChildren(catalog));
this.catalog=catalog;
getCookieSet().add(this);
if (catalog instanceof CatalogDescriptorBase) {
// set node properties acording to descriptor
CatalogDescriptorBase desc = (CatalogDescriptorBase) catalog;
setSynchronizeName(false);
setName(desc.getDisplayName());
String bundleString = catalog instanceof CatalogWriter ?"LBL_catalogReadWrite":"LBL_catalogReadOnly"; //NOI18N
setDisplayName(NbBundle.getMessage(CatalogNode.class, bundleString, desc.getDisplayName()));
setShortDescription(desc.getShortDescription());
fireIconChange();
// listen on it
desc.addPropertyChangeListener(WeakListeners.propertyChange(this, desc));
}
}
boolean isRemovable() {
CatalogReader reader = (CatalogReader)getBean();
if (CatalogSettings.getDefault().isRemovable(reader)) {
return true;
}
return false;
}
CatalogReader getCatalogReader() {
return catalog;
}
public Action[] getActions(boolean context) {
if (catalog instanceof CatalogWriter)
return new Action[] {
SystemAction.get(AddCatalogEntryAction.class),
SystemAction.get(RefreshAction.class),
SystemAction.get(CatalogNode.UnmountAction.class),
null,
//??? #24349 CustimizeAction sometimes added by BeanNode here
SystemAction.get(PropertiesAction.class)
};
else
return new Action[] {
SystemAction.get(RefreshAction.class),
SystemAction.get(CatalogNode.UnmountAction.class),
null,
//??? #24349 CustimizeAction sometimes added by BeanNode here
SystemAction.get(PropertiesAction.class)
};
}
/**
* @return icon returned by CatalogDescriptorBase if instance of it
*/
public Image getIcon(int type) {
if (catalog instanceof CatalogDescriptor2) {
String iconResource = ((CatalogDescriptor2)catalog).getIconResource(type);
if (iconResource != null) {
// will cache
return ImageUtilities.loadImage(iconResource, true);
}
}
if (catalog instanceof CatalogDescriptor) {
Image icon = ((CatalogDescriptor)catalog).getIcon(type);
if (icon != null) return icon;
}
try {
BeanInfo catalogInfo = Introspector.getBeanInfo(catalog.getClass());
Image icon = catalogInfo.getIcon(type);
if (icon != null) {
return icon;
}
} catch (IntrospectionException ex) {
Exceptions.printStackTrace(ex);
}
return super.getIcon(type);
}
public HelpCtx getHelpCtx() {
//return new HelpCtx(CatalogNode.class);
return HelpCtx.DEFAULT_HELP;
}
/**
* Refresh catalog provider and then refresh children.
*/
public void refresh() {
catalog.refresh();
((CatalogChildren)getChildren()).reload(); // may be double reload
}
/** This node cannot be destroyed, just unmount.
* @return always <CODE>false</CODE>
*/
public boolean canDestroy () {
return false;
}
public boolean canRename() {
return false;
}
/**
* Remove itseld from CatalogSettings,
*/
public void destroy() throws IOException {
CatalogSettings mounted = CatalogSettings.getDefault();
mounted.removeCatalog(catalog);
super.destroy();
}
/**
* The node listens on some changes
*/
public void propertyChange(PropertyChangeEvent e) {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(e.toString());
if (CatalogDescriptorBase.PROP_CATALOG_NAME.equals(e.getPropertyName())) {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" Setting name: " + (String) e.getNewValue()); // NOI18N
setName((String) e.getNewValue());
setDisplayName((String) e.getNewValue());
} else if (CatalogDescriptorBase.PROP_CATALOG_DESC.equals(e.getPropertyName())) {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" Setting desc: " + (String) e.getNewValue()); // NOI18N
setShortDescription((String) e.getNewValue());
} else if (CatalogDescriptorBase.PROP_CATALOG_ICON.equals(e.getPropertyName())) {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" Updating icon"); // NOI18N
fireIconChange();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~ Serialization stuff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("Reading Catalog node " + this); // NOI18N
in.defaultReadObject();
}
private void writeObject(ObjectOutputStream out) throws IOException {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("Writing " + this); // NOI18N
out.defaultWriteObject();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Kids have to listen at Catalog
*/
public static class CatalogChildren extends Children.Keys {
private CatalogReader peer;
private CatalogListener catalogListener;
public CatalogChildren(CatalogReader catalog) {
peer = catalog;
}
/** Contains public ID (String) instances. */
private final Set<String> keys = new TreeSet<>();
public void addNotify() {
catalogListener = new Lis();
try {
peer.addCatalogListener(catalogListener);
} catch (UnsupportedOperationException ex) {
// User must use explicit refresh
}
reload();
}
public void removeNotify() {
try {
peer.removeCatalogListener(catalogListener);
} catch (UnsupportedOperationException ex) {
// does not matter
}
keys.clear();
setKeys(keys);
}
public Node[] createNodes(Object key) {
try {
CatalogEntry catalogEntry = new CatalogEntry((String) key, peer);
return new Node[] {
new CatalogEntryNode(catalogEntry)
};
} catch (IntrospectionException ex) {
return null;
}
}
/**
* Reloads catalog content
*/
public void reload() {
//if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" Reloading kids of " + peer + "..."); // NOI18N
Set<String> previous = new HashSet<>(keys);
keys.clear();
Iterator<String> it = peer.getPublicIDs();
if (it != null) {
while (it.hasNext()) {
String publicID = it.next();
keys.add(publicID);
if (previous.contains(publicID)) {
refreshKey(publicID); // recreate node, the systemId may have changed
}
}
}
setKeys(keys);
}
private class Lis implements CatalogListener {
/** Given public ID has changed - created. */
public void notifyNew(String publicID) {
keys.add(publicID);
setKeys(keys);
}
/** Given public ID has changed - disappeared. */
public void notifyRemoved(String publicID) {
keys.remove(publicID);
setKeys(keys);
}
/** Given public ID has changed. */
public void notifyUpdate(String publicID) {
refreshKey(publicID);
}
/** All entries are invalidated. */
public void notifyInvalidate() {
reload();
}
}
}
/**
* Give to the action your own name
*/
private static final class UnmountAction extends NodeAction {
/** Serial Version UID */
private static final long serialVersionUID = 3556006276357785484L;
public UnmountAction() {
}
public String getName() {
return NbBundle.getMessage(CatalogNode.class, "LBL_unmount");
}
public HelpCtx getHelpCtx() {
return new HelpCtx(UnmountAction.class);
}
protected boolean enable(Node[] activatedNodes) {
if (activatedNodes.length > 0) {
for (int i = 0; i<activatedNodes.length; i++) {
Node me = activatedNodes[i];
Object self = me.getCookie(CatalogNode.class);
if (self instanceof CatalogNode) {
return ((CatalogNode)self).isRemovable();
}
}
}
return false;
}
protected void performAction(Node[] activatedNodes) {
if (enable(activatedNodes) == false) return;
for (int i = 0; i<activatedNodes.length; i++) {
try {
Node me = activatedNodes[i];
CatalogNode self = me.getCookie(CatalogNode.class);
self.destroy();
} catch (IOException ex) {
//Util.THIS.debug("Cannot unmount XML entity catalog!", ex);
}
}
}
protected boolean asynchronous() {
return false;
}
}
}