1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.sf.statcvs.renderer;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.NoSuchElementException;
31
32 import net.sf.statcvs.util.IntegerMap;
33
34 /**
35 * Groups a set of file names by directory. Provides a list
36 * of directories in the file set, and lumps directories
37 * with only one file together with its parent directory.
38 *
39 * @author Richard Cyganiak
40 * @version $Id: FileCollectionFormatter.java,v 1.9 2008/04/02 11:22:15 benoitx Exp $
41 */
42 public class FileCollectionFormatter {
43
44 private final Collection files;
45 private final IntegerMap filesPerDir;
46 private final IntegerMap dirDepths;
47
48 /**
49 * Creates a new instance from a <code>Collection</code> of
50 * file names.
51 * @param files Collection containing the String representations of files
52 */
53 public FileCollectionFormatter(final Collection files) {
54 this.files = files;
55 filesPerDir = createFilesPerDirCount();
56 dirDepths = createDirDepths();
57 }
58
59 private IntegerMap createFilesPerDirCount() {
60 final IntegerMap result = new IntegerMap();
61 final Iterator it = files.iterator();
62 while (it.hasNext()) {
63 final String file = (String) it.next();
64 result.addInt(getDirectory(file), 1);
65 }
66 return result;
67 }
68
69 private IntegerMap createDirDepths() {
70 final IntegerMap result = new IntegerMap();
71 final Iterator it = filesPerDir.iteratorSortedByKey();
72 while (it.hasNext()) {
73 final String dir = (String) it.next();
74 result.put(dir, getDepth(dir));
75 }
76 return result;
77 }
78
79 /**
80 * Gets a list of <code>String</code>s containing the
81 * directories in the file set, ordered by name.
82 * @return a list of <code>String</code>s containing the
83 * directories in the file set, ordered by name.
84 */
85 public List getDirectories() {
86 final List result = new ArrayList();
87 final Iterator it = dirDepths.iteratorSortedByKey();
88 while (it.hasNext()) {
89 final String directory = (String) it.next();
90 result.add(directory);
91 }
92 return result;
93 }
94
95 /**
96 * Gets the names of all files which reside in a given directory.
97 * The directory must be one from the {@link #getDirectories}
98 * list. Files will be relative to the directory. They will be
99 * ordered by name.
100 * @param directory to process
101 * @return the names of all files which reside in a given directory.
102 * The directory must be one from the {@link #getDirectories}
103 * list. Files will be relative to the directory. They will be
104 * ordered by name.
105 */
106 public List getFiles(final String directory) {
107 if (!dirDepths.contains(directory)) {
108 throw new NoSuchElementException("doesn't contain directory '" + directory + "'");
109 }
110 final List result = new ArrayList(getFilesInDir(directory));
111 Collections.sort(result);
112 final List allSubdirFiles = getFilesInSubdirs(directory);
113 Collections.sort(allSubdirFiles);
114 result.addAll(allSubdirFiles);
115 return result;
116 }
117
118 private List getFilesInSubdirs(final String directory) {
119 final List result = new ArrayList();
120 final Iterator it = files.iterator();
121 while (it.hasNext()) {
122 final String filename = (String) it.next();
123 if (isInDirectory(filename, directory) && !getDirectory(filename).equals(directory) && !isInDeeperDirectory(filename, directory)) {
124 result.add(getRelativeFilename(filename, directory));
125 }
126 }
127 return result;
128 }
129
130 private boolean isInDeeperDirectory(final String filename, final String directory) {
131 String currentDir = getDirectory(filename);
132 int currentDepth = getDepth(currentDir);
133 final int directoryDepth = getDepth(directory);
134 while (currentDepth > directoryDepth) {
135 if (dirDepths.contains(currentDir)) {
136 return true;
137 }
138 currentDepth--;
139 currentDir = getParent(currentDir);
140 }
141 return false;
142 }
143
144 private List getFilesInDir(final String directory) {
145 final List result = new ArrayList();
146 final Iterator it = files.iterator();
147 while (it.hasNext()) {
148 final String filename = (String) it.next();
149 if (getDirectory(filename).equals(directory)) {
150 result.add(getRelativeFilename(filename, directory));
151 }
152 }
153 return result;
154 }
155
156 /**
157 * Returns TRUE if file is in specified directroy, FALSE otherwise
158 * @param filename File to test
159 * @param directory Directory to test
160 * @return boolean TRUE if file is in specified directroy, FALSE otherwise
161 */
162 protected static boolean isInDirectory(final String filename, final String directory) {
163 return getDirectory(filename).startsWith(directory);
164 }
165
166 /**
167 * Returns relative filename for specified file and directory
168 * @param filename file
169 * @param dir directory
170 * @return String relative filename for specified file and directory
171 */
172 protected static String getRelativeFilename(final String filename, final String dir) {
173 return filename.substring(dir.length());
174 }
175
176 /**
177 * Returns directory name of specified file
178 * @param filename file to compute
179 * @return String directory name of specified file
180 */
181 protected static String getDirectory(final String filename) {
182 return filename.substring(0, filename.lastIndexOf("/") + 1);
183 }
184
185 /**
186 * Returns name of parent directory to specified directory
187 * @param directory to use
188 * @return String name of parent directory to specified directory
189 */
190 protected static String getParent(final String directory) {
191 final int lastIndex = directory.lastIndexOf("/");
192 if (lastIndex == -1) {
193 return "";
194 }
195 return directory.substring(0, directory.lastIndexOf("/", lastIndex - 1) + 1);
196 }
197
198 /**
199 * Returns the depth of the directory
200 * @param directory to be analysed
201 * @return int the depth of the directory
202 */
203 protected static int getDepth(final String directory) {
204 int result = 0;
205 int index = 0;
206 while (directory.indexOf("/", index) != -1) {
207 index = directory.indexOf("/", index) + 1;
208 result++;
209 }
210 return result;
211 }
212 }