001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.poifs.property;
019:
020: import java.util.*;
021:
022: import java.io.IOException;
023:
024: import org.apache.poi.poifs.storage.SmallDocumentBlock;
025:
026: /**
027: * Directory property
028: *
029: * @author Marc Johnson (mjohnson at apache dot org)
030: */
031:
032: public class DirectoryProperty extends Property implements Parent {
033:
034: // List of Property instances
035: private List _children;
036:
037: // set of children's names
038: private Set _children_names;
039:
040: /**
041: * Default constructor
042: *
043: * @param name the name of the directory
044: */
045:
046: public DirectoryProperty(String name) {
047: super ();
048: _children = new ArrayList();
049: _children_names = new HashSet();
050: setName(name);
051: setSize(0);
052: setPropertyType(PropertyConstants.DIRECTORY_TYPE);
053: setStartBlock(0);
054: setNodeColor(_NODE_BLACK); // simplification
055: }
056:
057: /**
058: * reader constructor
059: *
060: * @param index index number
061: * @param array byte data
062: * @param offset offset into byte data
063: */
064:
065: protected DirectoryProperty(final int index, final byte[] array,
066: final int offset) {
067: super (index, array, offset);
068: _children = new ArrayList();
069: _children_names = new HashSet();
070: }
071:
072: /**
073: * Change a Property's name
074: *
075: * @param property the Property whose name is being changed
076: * @param newName the new name for the Property
077: *
078: * @return true if the name change could be made, else false
079: */
080:
081: public boolean changeName(final Property property,
082: final String newName) {
083: boolean result;
084: String oldName = property.getName();
085:
086: property.setName(newName);
087: String cleanNewName = property.getName();
088:
089: if (_children_names.contains(cleanNewName)) {
090:
091: // revert the change
092: property.setName(oldName);
093: result = false;
094: } else {
095: _children_names.add(cleanNewName);
096: _children_names.remove(oldName);
097: result = true;
098: }
099: return result;
100: }
101:
102: /**
103: * Delete a Property
104: *
105: * @param property the Property being deleted
106: *
107: * @return true if the Property could be deleted, else false
108: */
109:
110: public boolean deleteChild(final Property property) {
111: boolean result = _children.remove(property);
112:
113: if (result) {
114: _children_names.remove(property.getName());
115: }
116: return result;
117: }
118:
119: public static class PropertyComparator implements Comparator {
120:
121: /**
122: * Object equality, implemented as object identity
123: *
124: * @param o Object we're being compared to
125: *
126: * @return true if identical, else false
127: */
128:
129: public boolean equals(Object o) {
130: return this == o;
131: }
132:
133: /**
134: * compare method. Assumes both parameters are non-null
135: * instances of Property. One property is less than another if
136: * its name is shorter than the other property's name. If the
137: * names are the same length, the property whose name comes
138: * before the other property's name, alphabetically, is less
139: * than the other property.
140: *
141: * @param o1 first object to compare, better be a Property
142: * @param o2 second object to compare, better be a Property
143: *
144: * @return negative value if o1 < o2,
145: * zero if o1 == o2,
146: * positive value if o1 > o2.
147: */
148:
149: public int compare(Object o1, Object o2) {
150: String VBA_PROJECT = "_VBA_PROJECT";
151: String name1 = ((Property) o1).getName();
152: String name2 = ((Property) o2).getName();
153: int result = name1.length() - name2.length();
154:
155: if (result == 0) {
156: // _VBA_PROJECT, it seems, will always come last
157: if (name1.compareTo(VBA_PROJECT) == 0)
158: result = 1;
159: else if (name2.compareTo(VBA_PROJECT) == 0)
160: result = -1;
161: else {
162: if (name1.startsWith("__")
163: && name2.startsWith("__")) {
164: // Betweeen __SRP_0 and __SRP_1 just sort as normal
165: result = name1.compareToIgnoreCase(name2);
166: } else if (name1.startsWith("__")) {
167: // If only name1 is __XXX then this will be placed after name2
168: result = 1;
169: } else if (name2.startsWith("__")) {
170: // If only name2 is __XXX then this will be placed after name1
171: result = -1;
172: } else
173: // result = name1.compareTo(name2);
174: // The default case is to sort names ignoring case
175: result = name1.compareToIgnoreCase(name2);
176: }
177: }
178: return result;
179: }
180: } // end private class PropertyComparator
181:
182: /* ********** START extension of Property ********** */
183:
184: /**
185: * @return true if a directory type Property
186: */
187:
188: public boolean isDirectory() {
189: return true;
190: }
191:
192: /**
193: * Perform whatever activities need to be performed prior to
194: * writing
195: */
196:
197: protected void preWrite() {
198: if (_children.size() > 0) {
199: Property[] children = (Property[]) _children
200: .toArray(new Property[0]);
201:
202: Arrays.sort(children, new PropertyComparator());
203: int midpoint = children.length / 2;
204:
205: setChildProperty(children[midpoint].getIndex());
206: children[0].setPreviousChild(null);
207: children[0].setNextChild(null);
208: for (int j = 1; j < midpoint; j++) {
209: children[j].setPreviousChild(children[j - 1]);
210: children[j].setNextChild(null);
211: }
212: if (midpoint != 0) {
213: children[midpoint]
214: .setPreviousChild(children[midpoint - 1]);
215: }
216: if (midpoint != (children.length - 1)) {
217: children[midpoint].setNextChild(children[midpoint + 1]);
218: for (int j = midpoint + 1; j < children.length - 1; j++) {
219: children[j].setPreviousChild(null);
220: children[j].setNextChild(children[j + 1]);
221: }
222: children[children.length - 1].setPreviousChild(null);
223: children[children.length - 1].setNextChild(null);
224: } else {
225: children[midpoint].setNextChild(null);
226: }
227: }
228: }
229:
230: /* ********** END extension of Property ********** */
231: /* ********** START implementation of Parent ********** */
232:
233: /**
234: * Get an iterator over the children of this Parent; all elements
235: * are instances of Property.
236: *
237: * @return Iterator of children; may refer to an empty collection
238: */
239:
240: public Iterator getChildren() {
241: return _children.iterator();
242: }
243:
244: /**
245: * Add a new child to the collection of children
246: *
247: * @param property the new child to be added; must not be null
248: *
249: * @exception IOException if we already have a child with the same
250: * name
251: */
252:
253: public void addChild(final Property property) throws IOException {
254: String name = property.getName();
255:
256: if (_children_names.contains(name)) {
257: throw new IOException("Duplicate name \"" + name + "\"");
258: }
259: _children_names.add(name);
260: _children.add(property);
261: }
262:
263: /* ********** END implementation of Parent ********** */
264: } // end public class DirectoryProperty
|