|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.xml.tree.nodes; import java.beans.*; import java.util.*; import java.awt.Component; import org.openide.nodes.*; import org.openide.util.actions.SystemAction; import org.openide.util.Lookup; import org.netbeans.tax.*; import org.netbeans.modules.xml.tree.lib.GuiUtil; import org.netbeans.modules.xml.tree.cookies.XMLNormalizeElementCookie; import org.netbeans.modules.xml.tree.actions.XMLNormalizeElementAction; import org.netbeans.modules.xml.tree.children.SubObjectListChildren; import org.netbeans.modules.xml.tree.completion.GrammarManager; import org.netbeans.modules.xml.tree.completion.TreeHintContext; import org.netbeans.modules.xml.api.model.HintContext; import org.netbeans.modules.xml.api.model.GrammarQuery; import org.netbeans.modules.xml.core.XMLDataObject; import org.openide.loaders.DataNode; import org.openide.loaders.DataObject; import org.w3c.dom.Attr; import org.w3c.dom.Element; /** * * @author Libor Kramolis * @version 0.1 */ public class ElementNode extends AbstractParentNode { /** * Fired when the customizer for this node changes * (e.g. the element name changes to something with a * different type of customizer) */ public static final String PROP_CUSTOMIZER = "customizer"; // NOI18N /** */ private static final String NODE_TYPE = "#element"; // NOI18N /** */ private static final int INDENT_STEP = 4; //??? -- it is only pilsen hack private static final String XML_ELEMENT_ICON = "/org/netbeans/modules/xml/tree/resources/elementNode.gif"; // NOI18N /** The element's customizer */ protected ElementCustomizer m_customizer; /** * A template to apply to the text accompanying this ode. * The pattern is specified in the doctype map. */ protected ElementTextFormatter m_nodeTextFormatter; /** * A flag used to instantiate the node's customizer * as lazily as possible. */ private boolean m_bInitializedCustomizer = false; // // init // /** */ public ElementNode (TreeElement treeElement) throws IntrospectionException { super (treeElement, new SubObjectListChildren (treeElement.getChildNodes(), treeElement.getAttributes(), null), "elementNode"); // NOI18N init(); } public Component getCustomizer() { if( !m_bInitializedCustomizer ) { // we haven't loaded the customizer // implementation yet... refreshGUI(true); } if( m_customizer == null ) { return super.getCustomizer(); } else { return m_customizer; } } protected ElementTextFormatter getElementTextFormatter() { if( m_nodeTextFormatter == null ) { m_nodeTextFormatter = new ElementTextFormatter(); } return m_nodeTextFormatter; } /** * Make this property writable, so it can be set * from a properties file. */ public void setCustomizer( ElementCustomizer c ) { if( m_customizer != c ) { Object oldCustomizer = m_customizer; m_customizer = c; if( m_customizer != null ) { m_customizer.setObject(this); } firePropertyChange( PROP_CUSTOMIZER, oldCustomizer, c ); } } /** * Bean property for the list of possible attributes * on this element (if a DTD or schema is available). * If no syntax completion is available, this will be * an empty List. * * @return A List of org.w3c.dom.Attr objects */ public List getAllowableAttributes() { XMLDataObject dataObject = (XMLDataObject)getCookie(DataObject.class); if (dataObject == null) return Collections.EMPTY_LIST; GrammarQuery query = GrammarManager.getGrammar(dataObject); HintContext ctx = TreeHintContext.getContext( getElement(), "" ); Enumeration en = query.queryAttributes(ctx); List result = new LinkedList(); while( en.hasMoreElements() ) { result.add(en.nextElement()); } return result; } /** */ private void init () { CookieSet set = getCookieSet(); CookieSet.Factory factory = new CookieFactory(); set.add (XMLNormalizeElementCookie.class, factory); // set.add (GenerateDTDSupport.class, factory); refreshGUI(false); getElement().addPropertyChangeListener(new ElementNode.Listener()); } /** * @param bCustomizer if true, call setCustomizer (for startup * and PROP_CUSTOMIZER events, but avoid the overhead otherwise) */ protected void refreshGUI(boolean bCustomizer) { // choose icon and customizer according to "doctype namespace" String sDocType = getDocumentType(getElement().getOwnerDocument()); String uriType = getElement().getNamespaceURI(); String sTagName = createName(); getElementTextFormatter().setTagName(sTagName); //??? could not it be perfomance problem, I guess // that it should be ported to naming or cached Lookup.Result lookupResult = Lookup.getDefault().lookup( new Lookup.Template( DoctypeElementMap.class ) ); Iterator iter = lookupResult.allInstances().iterator(); while( iter.hasNext() ) { DoctypeElementMap dtc = (DoctypeElementMap)iter.next(); if(sDocType != null && sDocType.equals(dtc.getDoctype()) || uriType != null && uriType.equals(dtc.getNamespaceURI())) { ElementInfo info = dtc.getElementInfo(sTagName); if( info != null ) { if( info.getIconBase() == null ) { // use the standard 'element' icon setIconBase(XML_ELEMENT_ICON); } else { // use the icon from the map file // for this doctype setIconBase(info.getIconBase()); } // if this is null, the getCustomizer // accessor will defer to the standard // element customizer if( bCustomizer ) { if( m_bInitializedCustomizer ) { setCustomizer(info.getCustomizer()); } else { // if we're just initializing now, we // want to avoid firing a PROP_CUSTOMIZER // event m_bInitializedCustomizer = true; m_customizer = info.getCustomizer(); if( m_customizer != null ) { m_customizer.setObject(this); } } } if( info.getText() == null ) { getElementTextFormatter().setPattern(null); } else { getElementTextFormatter().setPattern(info.getText()); } } return; } } } // // itself // /** */ public final TreeElement getElement () { return (TreeElement) getTreeObject(); } /** */ protected boolean canAddTreeObject (TreeObject newObject) { if ( newObject instanceof TreeAttribute ) { return true; } else if ( newObject instanceof TreeNamedObjectMap ) { return true; } else { return super.canAddTreeObject (newObject); } } /** */ protected boolean addTreeObject (TreeObject newObject) { if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\n=- ElementNode::addTreeObject: newObject = " + newObject); // NOI18N if ( newObject instanceof TreeAttribute ) { return addAttribute ((TreeAttribute)newObject); } else if ( newObject instanceof TreeNamedObjectMap ) { return addAttributeList ((TreeNamedObjectMap)newObject); } else if ( newObject instanceof TreeCharacterData ) { return super.addTreeObject (newObject); } else { try { TreeChild lastChild = getElement().getLastChild(); TreeObjectList objectList = getElement().getChildNodes(); TreeText indentText = null; int indent = findIndent (getElement()); // indent before add if ( lastChild instanceof TreeCharacterData ) { if ( ( lastChild instanceof TreeText ) && ((TreeText)lastChild).onlyWhiteSpaces() ) { indent ((TreeText)lastChild, indent + INDENT_STEP); } } else { indentText = new TreeText ("\n" + createIndent (indent + INDENT_STEP)); // NOI18N objectList.add (indentText); } objectList.add (newObject); // indent after add indentText = new TreeText ("\n" + createIndent (indent)); // NOI18N objectList.add (indentText); return true; } catch (TreeException exc) { GuiUtil.notifyWarning (exc.getMessage()); return false; } } } /** */ private void indent (TreeText text, int indent) throws TreeException { if ( text == null ) { return; } String data = text.getData(); StringBuffer dataSB = new StringBuffer (data); int lnl = data.lastIndexOf ('\n'); if ( lnl != -1 ) { indent -= (data.length() - lnl - 1); } else { dataSB.append ('\n'); } dataSB.append (createIndent (indent)); text.setData (dataSB.toString()); } /** */ private int findIndent (TreeChild child) { int indent = 0; TreeParentNode parent = child.getParentNode(); while ( parent instanceof TreeElement ) { indent += INDENT_STEP; parent = parent.getParentNode(); } return indent; } /** */ private String createIndent (int indent) { StringBuffer sb = new StringBuffer (); for (int i = 0; i < indent; i++) { sb.append (' '); } return sb.toString(); } /** */ protected boolean addAttributeList (TreeNamedObjectMap attributeList) { if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\n=+ ElementNode::addAttributeList: attributeList = " + attributeList); // NOI18N boolean allAdded = true; Iterator it = attributeList.iterator(); while (it.hasNext()) { Object next = it.next(); if ( next instanceof TreeAttribute ) { allAdded &= addAttribute ((TreeAttribute)next); } else { allAdded = false; } } return allAdded; } /** */ protected boolean addAttribute (TreeAttribute attribute) { if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug ("\n=# ElementNode::addAttribute: attribute = " + attribute); // NOI18N try { boolean toSet = true; TreeAttribute oldAttribute = getElement().getAttribute (attribute.getQName()); if ( oldAttribute != null ) { toSet = GuiUtil.confirmAction (Util.THIS.getString ("MSG_replace_attribute", attribute.getQName())); } if ( toSet ) { getElement().addAttribute (attribute); return true; } } catch (TreeException exc) { GuiUtil.notifyTreeException (exc); } return false; } // // Order // /** */ protected boolean canChangeOrder () { return true; } // // from AbstractObjectNode // /** Name of property used as node name. Used to listen on it. */ protected final String getPresentableNamePropertyName () { return TreeElement.PROP_TAG_NAME; } /** */ protected final void setPresentableNameProperty (String name) throws TreeException { getElement().setQName (name); } /** */ public String getDisplayName() { List attributes = getAllowableAttributes(); if( attributes.size() != 0 ) { String[] attValues = new String[attributes.size()]; Iterator iter = attributes.iterator(); int i=0; while( iter.hasNext() ) { Attr domAttr = (Attr)iter.next(); TreeAttribute attr = getElement().getAttribute(domAttr.getName()); if( attr != null ) { attValues[i++] = attr.getValue(); } else { attValues[i++] = ""; //NOI8N } } return getElementTextFormatter().format( attributes, attValues ); } // if the above didn't work out (for whatever reason) // just use the back-off strategy (the name of the element) return super.getDisplayName(); } /** */ protected final String createName () { return getElement().getQName(); } /** */ protected final String createNodePreview () { StringBuffer sb = new StringBuffer(); sb.append ("<").append (getElement().getQName()).append (" ... />"); // NOI18N return sb.toString(); } /** */ protected final String getNodeTypePrefix () { return NODE_TYPE; } /** */ protected final SystemAction[] createNodeSpecificActions () { return new SystemAction[] { // SystemAction.get (XMLGenerateAction.GenerateDTDAction.class), SystemAction.get (XMLNormalizeElementAction.class), }; } // // NewTypes // /** */ protected Object[] getNewTypesTypes () { XMLDataObject dataObject = (XMLDataObject)getCookie(DataObject.class); if (dataObject == null) return new Object[0]; GrammarQuery query = GrammarManager.getGrammar(dataObject); HintContext ctx = TreeHintContext.getContext( getElement(), "" ); Enumeration en = query.queryElements(ctx); List elementList = new LinkedList(); while( en.hasMoreElements() ) { elementList.add(en.nextElement()); } // TODO: query for allowable text children return elementList.toArray(); } /** * Try to get the doctype from the DTD declaration, or the string * representing the root namespace for a document using schemas. */ private static String getDocumentType( TreeDocumentRoot root ) { if( root instanceof TreeDocument ) { // try the DTD first TreeDocumentType docType = ((TreeDocument)root).getDocumentType(); if( docType != null ) { return docType.getPublicId(); } // try the schema's default namespace TreeElement rootElement = ((TreeDocument)root).getDocumentElement(); TreeAttribute defaultNS = rootElement.getAttribute("xmlns"); // NOI18N if( defaultNS != null ) { return defaultNS.getValue(); } } return ""; } // // XMLNormalizeElementCookie // /** * */ private class InnerCookieImpl implements XMLNormalizeElementCookie { /** */ public final void normalize () { try { GuiUtil.setStatusText (Util.THIS.getString ("MSG_normalize_start")); ElementNode.this.getElement().normalize(); GuiUtil.setStatusText (Util.THIS.getString ("MSG_normalizeFinished")); } catch (TreeException exc) { GuiUtil.setStatusText (Util.THIS.getString ("MSG_normalize_error")); GuiUtil.notifyTreeException (exc); } } } // end: class InnerCookieImpl // // class CookieFactory // /** * */ private class CookieFactory implements CookieSet.Factory { /** Creates new Cookie */ public Node.Cookie createCookie (Class clazz) { if ( clazz == XMLNormalizeElementCookie.class ) { return new InnerCookieImpl(); // } else if ( clazz == GenerateDTDSupport.class ) { // return new GenerateDTDSupport (ElementNode.this, ElementNode.this.getElement()); } return null; } } private class Listener implements PropertyChangeListener { public void propertyChange( PropertyChangeEvent evt ) { if( m_bChangeInProgress ) { return; } if( evt.getSource() != ElementNode.this.getElement() || evt.getPropertyName() == null ) { return; } if( evt.getPropertyName().equals(TreeElement.PROP_TAG_NAME) || evt.getPropertyName().equals(TreeElement.PROP_ATTRIBUTES) ) { try { m_bChangeInProgress = true; ElementNode.this.refreshGUI( evt.getPropertyName().equals( TreeElement.PROP_TAG_NAME) ); } finally { m_bChangeInProgress = false; } } } private boolean m_bChangeInProgress = false; } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.