/* * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ package no.geosoft.cc.directory; import java.util.*; /** * A class representing a generic folder node within a directory * structure. A folder may contain DirectoryEnty children and may * have a client specified item back-end object. * * @author <a href="mailto:info@geosoft.no">GeoSoft</a> */ public class Folder extends DirectoryEntry { private List entries_; // of DirectoryEntry private boolean isExpanded_; /** * Create a new folder entry. * * @param item Client specific item of the folder. * @param name Name of the folder. */ public Folder (Object item, String name) { super (item, name); entries_ = new ArrayList(); isExpanded_ = false; } /** * Create a folder with name according to item toString(). * * @param item Client specific item of the folder. */ public Folder (Object item) { this (item, item.toString()); } /** * Create a namelsee and itemless folder entry. * * @return */ public Folder() { this (null, null); } /** * Add an entry to this folder at a specific position. * NOTE: Entries can have one parent only. * * @param entry Entry to add. * @param index Entry position, 0 is first, etc. */ public void add (DirectoryEntry entry, int index) { entry.setParent (this); entries_.add (index, entry); } /** * Add an entry to the end of this folder. * * @param entry Entry to add. */ public void add (DirectoryEntry entry) { add (entry, getNEntries()); } /** * Add a set of entries to this folder. * * @param entries Entries to add. */ public void add (Collection entries) { for (Iterator i = entries.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); add (entry); } } /** * Add an entry sorted alphabetically according to the entrys * toString() method. * * @param entry Entry to add. */ public void addSorted (DirectoryEntry entry) { int index = 0; for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry existingEntry = (DirectoryEntry) i.next(); if (existingEntry.compareTo (entry) > 0) break; index++; } add (entry, index); } /** * Add a set of entries sorted alphabetically according to the entries' * toString() method. * * @param entry Entry to add. */ public void addSorted (Collection entries) { for (Iterator i = entries.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); addSorted (entry); } } /** * Remove entry from this folder. * * @param entry Entry to remove. */ public void remove (DirectoryEntry entry) { // Everybody that "is" this instance must be removed as well entry.removeSymbolicLinks(); // Remove from child list entries_.remove (entry); } /** * Return true if this is a leaf node. A folder is per definition not * a leaf node even if empty, so this method always return false. * * @return False always. */ public boolean isLeaf() { return false; // Per definition, even if it is empty } /** * Return true if this is a root node. A node is root if it doesn't * have a parent node. * * @return True if this is a root node, false otherwise. */ public boolean isRoot() { return getParent() == null; } /** * Return the child entry at the specific position. Return null * if the entry does not exists. * * @param index Position of entry to return. * @return */ public DirectoryEntry getEntry (int index) { if (index < 0 || index > entries_.size()-1) return null; else return (DirectoryEntry) entries_.get (index); } /** * Staring from this node, return the index'th element in the * tree, traversing depth first. * * @param entryNo Entry number to find. * @return */ public DirectoryEntry getGlobalEntry (int entryNo) { Vector list = new Vector(); return getGlobalEntry (entryNo, list); } private DirectoryEntry getGlobalEntry (int entryNo, Vector list) { if (list.size() == entryNo) return this; list.add (this); for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry subEntry = (DirectoryEntry) i.next(); if (subEntry.isFolder()) { Folder folder = (Folder) subEntry; DirectoryEntry foundEntry = folder.getGlobalEntry (entryNo, list); if (foundEntry != null) return foundEntry; } else { if (list.size() == entryNo) return subEntry; list.add (subEntry); } } return null; } /** * Starting from here, return the entry number of the specified * entry traversing depth first. Return -1 if not found. * * @param entry Entry to find entry number of. * @return Entry number of specified entry (or -1 if not found). */ public int getGlobalIndexOfEntry (DirectoryEntry entry) { Vector list = new Vector(); boolean isFound = getGlobalIndexOfEntry (entry, list); return isFound ? list.size() : -1; } private boolean getGlobalIndexOfEntry (DirectoryEntry entry, Vector list) { if (this == entry) return true; list.add (this); for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry subEntry = (DirectoryEntry) i.next(); if (subEntry.isFolder()) { Folder folder = (Folder) subEntry; boolean isFound = folder.getGlobalIndexOfEntry (entry, list); if (isFound) return true; } else { list.add (subEntry); if (subEntry == entry) return true; } } return false; } /** * Return position of the specified entry. Null if entry does not * exist. * * @param entry Entry to find index of. * @return */ public int getIndexOfEntry (DirectoryEntry entry) { return entries_.indexOf (entry); } /** * Check if the folder is empty (has no children). * * @return True if the folder is empty, false otherwise. */ public boolean isEmpty() { return getNEntries() == 0; } /** * Return number of entries in this folder. * * @return Number of entries in this folder. */ public int getNEntries() { return entries_.size(); } /** * Get the entries of this folder. * * @return The entries of this folder (List of DirectoryEntry) */ public List getEntries() { return entries_; } /** * Recursively check if an entry is descendant of this folder. * * @param entry Entry to check. * @return True if the entry is a descendant of this folder, * false otherwise. */ public boolean contains (DirectoryEntry entry) { for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry subEntry = (DirectoryEntry) i.next(); if (subEntry == entry) return true; if (subEntry instanceof Folder && ((Folder)subEntry).contains (entry)) return true; } return false; } /** * Find a given node among the immediate children of this * folder. * * @param name Name of child to find. * @return Directory entry of searched node (or null if not found). */ public DirectoryEntry find (String name) { for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.getName().equals (name)) return entry; } return null; } /** * Find a given node within the entire subtree of this folder. * * @param name Name of node to find. * @return Directory entry of searched node (or null if not found). */ public DirectoryEntry findGlobal (String name) { if (getName().equals (name)) return this; for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry instanceof Folder) { DirectoryEntry foundEntry = ((Folder) entry).findGlobal (name); if (foundEntry != null) return foundEntry; } else { if (entry.getName().equals (name)) return entry; } } // Not found return null; } /** * Find a given folder among the immediate children of this * folder. * * @param name Name of folder to find. * @return The searched folder (or null if not found). */ public Folder findFolder (String name) { for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.isFolder() && entry.getName().equals (name)) return (Folder) entry; } return null; } private boolean isItemsEqual (Object o1, Object o2) { if (o1 == null) return o2 == null; else return o1.equals (o2); } /** * Return sub folder based on item value. Search the entire * sub tree from this folder. * * @param item Item of the folder to find. * @return Searched folder (or null if not found). */ public Folder findFolder (Object item) { if (getItem() == item) return this; for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.isFolder()) { Folder folder = (Folder) entry; Folder found = folder.findFolder (item); if (found != null) return found; } } // Not found return null; } /** * Return entry based on item value. Search the entire * sub tree from this folder. * * @param item Item of the entry to find. * @return Searched entry (or null if not found). */ public DirectoryEntry findEntry (Object item) { if (isItemsEqual (item, getItem())) return this; for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.isFolder()) { Folder folder = (Folder) entry; DirectoryEntry found = folder.findEntry (item); if (found != null) return found; } else { if (isItemsEqual (item, entry.getItem())) return entry; } } // Not found return null; } /** * Identify this folder as "expanded". This setting may be used * in a GUI front-end module. */ public void expand() { isExpanded_ = true; } /** * Identify this folder and all sub folders as "expanded". * This setting may be used in a GUI front-end module. */ public void expandAll() { // Expand this expand(); // Expand children folders for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.isFolder()) { Folder folder = (Folder) entry; folder.expandAll(); } } } /** * Identify this folder as "collapsed". This setting may be used * in a GUI front-end module. */ public void collapse() { isExpanded_ = false; } /** * Identify this folder and all sub folders as "collapsed". * This setting may be used in a GUI front-end module. */ public void collapseAll() { // Expand this collapse(); // Expand children folders for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); if (entry.isFolder()) { Folder folder = (Folder) entry; folder.collapseAll(); } } } // DEBUG public void print (int indent) { for (int i = 0; i < indent; i++) System.out.print (" "); System.out.println ("Folder: " + getName()); for (Iterator i = entries_.iterator(); i.hasNext(); ) { DirectoryEntry entry = (DirectoryEntry) i.next(); entry.print (indent + 2); } } }