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  64
     public FileCollectionFormatter(final Collection files) {
 54  64
         this.files = files;
 55  64
         filesPerDir = createFilesPerDirCount();
 56  64
         dirDepths = createDirDepths();
 57  64
     }
 58  
 
 59  
     private IntegerMap createFilesPerDirCount() {
 60  64
         final IntegerMap result = new IntegerMap();
 61  64
         final Iterator it = files.iterator();
 62  144
         while (it.hasNext()) {
 63  80
             final String file = (String) it.next();
 64  80
             result.addInt(getDirectory(file), 1);
 65  70
         }
 66  64
         return result;
 67  
     }
 68  
 
 69  
     private IntegerMap createDirDepths() {
 70  64
         final IntegerMap result = new IntegerMap();
 71  64
         final Iterator it = filesPerDir.iteratorSortedByKey();
 72  128
         while (it.hasNext()) {
 73  64
             final String dir = (String) it.next();
 74  64
             result.put(dir, getDepth(dir));
 75  56
         }
 76  64
         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  48
         final List result = new ArrayList();
 87  48
         final Iterator it = dirDepths.iteratorSortedByKey();
 88  104
         while (it.hasNext()) {
 89  56
             final String directory = (String) it.next();
 90  56
             result.add(directory);
 91  49
         }
 92  48
         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  64
         if (!dirDepths.contains(directory)) {
 108  8
             throw new NoSuchElementException("doesn't contain directory '" + directory + "'");
 109  
         }
 110  56
         final List result = new ArrayList(getFilesInDir(directory));
 111  56
         Collections.sort(result);
 112  56
         final List allSubdirFiles = getFilesInSubdirs(directory);
 113  56
         Collections.sort(allSubdirFiles);
 114  56
         result.addAll(allSubdirFiles);
 115  56
         return result;
 116  
     }
 117  
 
 118  
     private List getFilesInSubdirs(final String directory) {
 119  56
         final List result = new ArrayList();
 120  56
         final Iterator it = files.iterator();
 121  168
         while (it.hasNext()) {
 122  112
             final String filename = (String) it.next();
 123  112
             if (isInDirectory(filename, directory) && !getDirectory(filename).equals(directory) && !isInDeeperDirectory(filename, directory)) {
 124  0
                 result.add(getRelativeFilename(filename, directory));
 125  
             }
 126  98
         }
 127  56
         return result;
 128  
     }
 129  
 
 130  
     private boolean isInDeeperDirectory(final String filename, final String directory) {
 131  24
         String currentDir = getDirectory(filename);
 132  24
         int currentDepth = getDepth(currentDir);
 133  24
         final int directoryDepth = getDepth(directory);
 134  24
         while (currentDepth > directoryDepth) {
 135  24
             if (dirDepths.contains(currentDir)) {
 136  24
                 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  56
         final List result = new ArrayList();
 146  56
         final Iterator it = files.iterator();
 147  168
         while (it.hasNext()) {
 148  112
             final String filename = (String) it.next();
 149  112
             if (getDirectory(filename).equals(directory)) {
 150  72
                 result.add(getRelativeFilename(filename, directory));
 151  
             }
 152  98
         }
 153  56
         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  112
         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  128
         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  448
         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  24
         final int lastIndex = directory.lastIndexOf("/");
 192  24
         if (lastIndex == -1) {
 193  8
             return "";
 194  
         }
 195  16
         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  136
         int result = 0;
 205  136
         int index = 0;
 206  248
         while (directory.indexOf("/", index) != -1) {
 207  112
             index = directory.indexOf("/", index) + 1;
 208  112
             result++;
 209  
         }
 210  136
         return result;
 211  
     }
 212  
 }