![JAR search and dependency download from the Maven repository](/logo.png)
org.netbeans.modules.properties.Element 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.properties; import java.beans.*; import java.io.*; import javax.swing.text.BadLocationException; import org.openide.nodes.Node; import org.openide.ErrorManager; import org.openide.text.PositionBounds; /** * Base class for representations of elements in properties files. * * @author Petr Jiricka * @author Petr Kuzel - moved to nonescaped strings level * //!!! why is it serializable? */ public abstract class Element implements Serializable { /** Property change support */ private transient PropertyChangeSupport support = new PropertyChangeSupport(this); /** Position of the begin and the end of the element. Could * be null indicating the element is not part of properties structure yet. */ protected PositionBounds bounds; /** Create a new element. */ protected Element(PositionBounds bounds) { this.bounds = bounds; } /** Getter for bounds property. */ public PositionBounds getBounds() { return bounds; } /** * Updates the element fields. This method is called after reparsing. * @param elem the element to merge with */ void update(Element elem) { this.bounds = elem.bounds; } /** Fires property change event. * @param name property name * @param o old value * @param n new value */ protected final void firePropertyChange(String name, Object o, Object n) { support.firePropertyChange (name, o, n); } /** Adds property listener */ public void addPropertyChangeListener (PropertyChangeListener l) { support.addPropertyChangeListener (l); } /** Removes property listener */ public void removePropertyChangeListener (PropertyChangeListener l) { support.removePropertyChangeListener (l); } /** Prints this element (and all its subelements) by calling
andbounds.setText(...)
* Ifbounds
is null does nothing. * @see #bounds */ public final void print() { if (bounds == null) { return; } try { bounds.setText(getDocumentString()); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } catch (IOException e) { ErrorManager.getDefault().notify(e); } } /** * Get a string representation of the element for printing into Document. * It currently means that it's properly escaped. * @return the string in its Document form */ public abstract String getDocumentString(); /** * Get debug string of the element. * @return the string */ public String toString() { if (bounds == null) { return "(no bounds)"; } return new StringBuffer(16) .append('(') .append(bounds.getBegin().getOffset()) .append(", ") //NOI18N .append(bounds.getEnd().getOffset()) .append(')') .toString(); } /** General class for basic elements, which contain value directly. */ public static abstract class Basic extends Element { private static final String hexaDigitChars = "0123456789abcdefABCDEF"; //NOI18N protected static void appendIsoControlChar(final StringBuilder buf, final char c) { switch (c) { case '\t': buf.append('\\').append('t'); break; case '\n': buf.append('\\').append('n'); break; case '\f': buf.append('\\').append('f'); break; case '\r': buf.append('\\').append('r'); break; default: buf.append('\\').append('u'); for (int shift = 12; shift >= 0; shift -= 4) { buf.append(hexaDigitChars.charAt( ((c >> shift) & 0xf))); } } } /** Parsed value of the element */ protected String value; /** Create a new basic element. */ protected Basic(PositionBounds bounds, String value) { super(bounds); this.value = value; } /** * Updates the element fields. This method is called after reparsing. * @param elem elemnet to merge with */ void update(Element elem) { super.update(elem); this.value = ((Basic)elem).value; } /** Get a string representation of the element. * @return the string + bounds */ public String toString() { return value + " " + super.toString(); // NOI18N } /** * Get a value of the element. * @return the Java string (no escaping) */ public String getValue() { return value; } /** * Sets the value. Does not check if the value has changed. * The value is immediately propadated in text Document possibly * triggering DocumentEvents. * @param value Java string (no escaping) */ public void setValue(String value) { this.value = value; this.print(); } @Override public boolean equals(Object anObject) { if(this == anObject) { return true; } if(anObject instanceof Basic) { Basic b = (Basic)anObject; if(value == null) { return b.value == null; } return value.equals(b.value); } return false; } } // End of nested class Basic. /** Class representing key element in properties file. */ public static class KeyElem extends Basic { /** Generated serial version UID. */ static final long serialVersionUID =6828294289485744331L; /** Create a new key element. */ protected KeyElem(PositionBounds bounds, String value) { super(bounds, value); } /** Get a string representation of the key for printing. Treats the '=' sign as a part of the key * @return the string */ public String getDocumentString() { return escapeSpecialChars(value) + "="; //NOI18N } /** * * @author Marian Petras */ private static final String escapeSpecialChars(final String text) { StringBuilder buf = new StringBuilder(text.length() + 16); final int length = text.length(); for (int i = 0; i < length; i++) { char c = text.charAt(i); if (c < 0x20) { Basic.appendIsoControlChar(buf, c); } else { switch (c) { case '#': case '!': if (i == 0) { buf.append('\\'); } break; case ' ': case '=': case ':': case '\\': buf.append('\\'); break; } buf.append(c); } } return buf.toString(); } @Override public boolean equals(Object anObject) { return anObject instanceof KeyElem && super.equals(anObject); } } // End of nested class KeyElem. /** Class representing value element in properties files. */ public static class ValueElem extends Basic { /** Generated serial version UID. */ static final long serialVersionUID =4662649023463958853L; /** Create a new value element. */ protected ValueElem(PositionBounds bounds, String value) { super(bounds, value); } /** Get a string representation of the value for printing. Appends end of the line after the value. * @return the string */ public String getDocumentString() { // escape outerspaces and continious line marks return escapeSpecialChars(value) + "\n"; //NOI18N } /** * * @author Marian Petras */ private static final String escapeSpecialChars(final String text) { StringBuilder buf = new StringBuilder(text.length() + 16); boolean isInitialWhitespace = true; final int length = text.length(); for (int i = 0; i < length; i++) { char c = text.charAt(i); boolean escape = false; if (c == '\\') { isInitialWhitespace = false; escape = true; } else if (isInitialWhitespace) { if (c == ' ') { escape = true; } else { isInitialWhitespace = (c == '\t') || (c == '\r') || (c == '\n') || (c == '\f'); } } if (c < 0x20) { Basic.appendIsoControlChar(buf, c); } else { if (escape) { buf.append('\\'); } buf.append(c); } } return buf.toString(); } } // End of nested class ValueElem. /** * Class representing comment element in properties files.null
values of the * string are legal and indicate that the comment is empty. It should contain * pure comment string without comment markers. */ public static class CommentElem extends Basic { /** Genererated serial version UID. */ static final long serialVersionUID =2418308580934815756L; /** * Create a new comment element. * @param value Comment without its markers (leading '#' or '!'). Markers * are automatically prepended while writing it down to Document. */ protected CommentElem(PositionBounds bounds, String value) { super(bounds, value); } /** Get a string representation of the comment for printing. Makes sure every non-empty line starts with a # and * that the last line is terminated with an end of line marker. * @return the string */ public String getDocumentString() { if (value == null || value.length() == 0) return ""; // NOI18N else { // insert #s at the beginning of the lines which contain non-blank characters // holds the last position where we might have to insert a # if this line contains non-blanks StringBuffer sb = new StringBuffer(value); // append the \n if missing if (sb.charAt(sb.length() - 1) != '\n') { sb.append('\n'); } int lineStart = 0; boolean hasCommentChar = false; for (int i=0; ikey value
may be null. */ protected ItemElem(PositionBounds bounds, KeyElem key, ValueElem value, CommentElem comment) { super(bounds); this.key = key; this.value = value; this.comment = comment; } /** Sets the parent of this element. */ void setParent(PropertiesStructure ps) { parent = ps; } /** Gets parent. * @exception IllegalStateException if the parent isnull
. */ private PropertiesStructure getParent() { if(parent == null) { throw new IllegalStateException("Resource Bundle: Parent is missing"); // NOI18N } return parent; } /** Get a value string of the element. * @return the string */ public String toString() { return comment.toString() + "\n" + // NOI18N ((key == null) ? "" : key.toString()) + "\n" + // NOI18N ((value == null) ? "" : value.toString()) + "\n"; // NOI18N } /** Returns the key element for this item. */ public KeyElem getKeyElem() { return key; } /** Returns the value element for this item. */ public ValueElem getValueElem() { return value; } /** Returns the comment element for this item. */ public CommentElem getCommentElem() { return comment; } void update(Element elem) { super.update(elem); if (this.key == null) this.key = ((ItemElem)elem).key; else this.key.update(((ItemElem)elem).key); if (this.value == null) this.value = ((ItemElem)elem).value; else this.value.update(((ItemElem)elem).value); this.comment.update(((ItemElem)elem).comment); } public String getDocumentString() { return comment.getDocumentString() + ((key == null) ? "" : key.getDocumentString()) + // NOI18N ((value == null) ? "" : value.getDocumentString()); // NOI18N } /** Get a key by which to identify this record * @return nonescaped key */ public String getKey() { return (key == null) ? null : key.getValue(); } /** Set the key for this item * @param newKey nonescaped key */ public void setKey(String newKey) { String oldKey = key.getValue(); if (!oldKey.equals(newKey)) { key.setValue(newKey); getParent().itemKeyChanged(oldKey, this); this.firePropertyChange(PROP_ITEM_KEY, oldKey, newKey); } } /** Get the value of this item */ public String getValue() { return (value == null) ? null : value.getValue(); } /** Set the value of this item * @param newValue the new value */ public void setValue(String newValue) { String oldValue = value.getValue(); if (!oldValue.equals(newValue)) { if(oldValue.equals("")) // NOI18N // Reprint key for the case it's alone yet and doesn't have seprator after (= : or whitespace). key.print(); value.setValue(newValue); getParent().itemChanged(this); this.firePropertyChange(PROP_ITEM_VALUE, oldValue, newValue); } } /** Get the comment for this item */ public String getComment() { return (comment == null) ? null : comment.getValue(); } /** Set the comment for this item * @param newComment the new comment (escaped value) * //??? why is required escaped value? I'd expect escapng to be applied during * writing value down to stream no earlier */ public void setComment(String newComment) { String oldComment = comment.getValue(); if ((oldComment == null && newComment != null) || (oldComment != null && !oldComment.equals(newComment))) { comment.setValue(newComment); getParent().itemChanged(this); this.firePropertyChange(PROP_ITEM_COMMENT, oldComment, newComment); } } /** Checks for equality of two ItemElem-s */ public boolean equals(Object item) { if (item == null || !(item instanceof ItemElem)) return false; ItemElem ie = (ItemElem)item; return isKeyEqual(ie) && isValueEqual(ie) && isCommentEqual(ie); } private boolean isKeyEqual(ItemElem ie) { if(key==null) { return ie.key==null; } return key.equals(ie.key); } private boolean isValueEqual(ItemElem ie) { if(value==null) { return ie.value==null; } return value.equals(ie.value); } private boolean isCommentEqual(ItemElem ie) { if(comment==null) { return ie.comment==null; } return comment.equals(ie.comment); } } // End of nested class ItemElem. }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy