Coverage Report - net.sf.statcvs.renderer.FileCollectionFormatter
 
Classes in this File Line Coverage Branch Coverage Complexity
FileCollectionFormatter
94%
68/72
89%
25/28
2.154
 
 1  
 /*
 2  
     StatCvs - CVS statistics generation 
 3  
     Copyright (C) 2002  Lukasz Pekacki <lukasz@pekacki.de>
 4  
     http://statcvs.sf.net/
 5  
     
 6  
     This library is free software; you can redistribute it and/or
 7  
     modify it under the terms of the GNU Lesser General Public
 8  
     License as published by the Free Software Foundation; either
 9  
     version 2.1 of the License, or (at your option) any later version.
 10  
 
 11  
     This library is distributed in the hope that it will be useful,
 12  
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  
     Lesser General Public License for more details.
 15  
 
 16  
     You should have received a copy of the GNU Lesser General Public
 17  
     License along with this library; if not, write to the Free Software
 18  
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  
     
 20  
         $RCSfile: FileCollectionFormatter.java,v $ 
 21  
         Created on $Date: 2008/04/02 11:22:15 $ 
 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  48
     public FileCollectionFormatter(final Collection files) {
 54  48
         this.files = files;
 55  48
         filesPerDir = createFilesPerDirCount();
 56  48
         dirDepths = createDirDepths();
 57  48
     }
 58  
 
 59  
     private IntegerMap createFilesPerDirCount() {
 60  48
         final IntegerMap result = new IntegerMap();
 61  48
         final Iterator it = files.iterator();
 62  108
         while (it.hasNext()) {
 63  60
             final String file = (String) it.next();
 64  60
             result.addInt(getDirectory(file), 1);
 65  50
         }
 66  48
         return result;
 67  
     }
 68  
 
 69  
     private IntegerMap createDirDepths() {
 70  48
         final IntegerMap result = new IntegerMap();
 71  48
         final Iterator it = filesPerDir.iteratorSortedByKey();
 72  96
         while (it.hasNext()) {
 73  48
             final String dir = (String) it.next();
 74  48
             result.put(dir, getDepth(dir));
 75  40
         }
 76  48
         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  36
         final List result = new ArrayList();
 87  36
         final Iterator it = dirDepths.iteratorSortedByKey();
 88  78
         while (it.hasNext()) {
 89  42
             final String directory = (String) it.next();
 90  42
             result.add(directory);
 91  35
         }
 92  36
         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  48
         if (!dirDepths.contains(directory)) {
 108  6
             throw new NoSuchElementException("doesn't contain directory '" + directory + "'");
 109  
         }
 110  42
         final List result = new ArrayList(getFilesInDir(directory));
 111  42
         Collections.sort(result);
 112  42
         final List allSubdirFiles = getFilesInSubdirs(directory);
 113  42
         Collections.sort(allSubdirFiles);
 114  42
         result.addAll(allSubdirFiles);
 115  42
         return result;
 116  
     }
 117  
 
 118  
     private List getFilesInSubdirs(final String directory) {
 119  42
         final List result = new ArrayList();
 120  42
         final Iterator it = files.iterator();
 121  126
         while (it.hasNext()) {
 122  84
             final String filename = (String) it.next();
 123  84
             if (isInDirectory(filename, directory) && !getDirectory(filename).equals(directory) && !isInDeeperDirectory(filename, directory)) {
 124  0
                 result.add(getRelativeFilename(filename, directory));
 125  
             }
 126  70
         }
 127  42
         return result;
 128  
     }
 129  
 
 130  
     private boolean isInDeeperDirectory(final String filename, final String directory) {
 131  18
         String currentDir = getDirectory(filename);
 132  18
         int currentDepth = getDepth(currentDir);
 133  18
         final int directoryDepth = getDepth(directory);
 134  18
         while (currentDepth > directoryDepth) {
 135  18
             if (dirDepths.contains(currentDir)) {
 136  18
                 return true;
 137  
             }
 138  0
             currentDepth--;
 139  0
             currentDir = getParent(currentDir);
 140  
         }
 141  0
         return false;
 142  
     }
 143  
 
 144  
     private List getFilesInDir(final String directory) {
 145  42
         final List result = new ArrayList();
 146  42
         final Iterator it = files.iterator();
 147  126
         while (it.hasNext()) {
 148  84
             final String filename = (String) it.next();
 149  84
             if (getDirectory(filename).equals(directory)) {
 150  54
                 result.add(getRelativeFilename(filename, directory));
 151  
             }
 152  70
         }
 153  42
         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  84
         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  96
         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  336
         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  18
         final int lastIndex = directory.lastIndexOf("/");
 192  18
         if (lastIndex == -1) {
 193  6
             return "";
 194  
         }
 195  12
         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  102
         int result = 0;
 205  102
         int index = 0;
 206  186
         while (directory.indexOf("/", index) != -1) {
 207  84
             index = directory.indexOf("/", index) + 1;
 208  84
             result++;
 209  
         }
 210  102
         return result;
 211  
     }
 212  
 }