BookSet.java |
1 /** 2 * Distribution License: 3 * JSword is free software; you can redistribute it and/or modify it under 4 * the terms of the GNU Lesser General Public License, version 2.1 or later 5 * as published by the Free Software Foundation. This program is distributed 6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even 7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 8 * See the GNU Lesser General Public License for more details. 9 * 10 * The License is available on the internet at: 11 * http://www.gnu.org/copyleft/lgpl.html 12 * or by writing to: 13 * Free Software Foundation, Inc. 14 * 59 Temple Place - Suite 330 15 * Boston, MA 02111-1307, USA 16 * 17 * © CrossWire Bible Society, 2005 - 2016 18 * 19 */ 20 package org.crosswire.jsword.book; 21 22 import java.util.ArrayList; 23 import java.util.Collection; 24 import java.util.Collections; 25 import java.util.Iterator; 26 import java.util.Set; 27 import java.util.TreeSet; 28 29 import org.crosswire.common.util.Filter; 30 31 /** 32 * BookSet represents a collection of descriptions about Books which may be 33 * subsetted into other BookMetaDataSets. Each set is naturally ordered. 34 * 35 * @see gnu.lgpl.License The GNU Lesser General Public License for details. 36 * @author DM Smith 37 */ 38 public class BookSet extends ArrayList<Book> implements Set<Book> { 39 public BookSet() { 40 } 41 42 public BookSet(Collection<Book> books) { 43 this(); 44 addAll(books); 45 } 46 47 /** 48 * Gets the sorted set of all keys which can be used for groupings. These 49 * are all the property keys across the BookMetaDatas in this list. 50 * 51 * @return the set of all keys which can be used for grouping. 52 */ 53 public Set<String> getGroups() { 54 Set<String> results = new TreeSet<String>(); 55 for (Book book : this) { 56 results.addAll(book.getPropertyKeys()); 57 } 58 return results; 59 } 60 61 /** 62 * Get the sorted set of all values for a particular key. If there is a 63 * BookMetaData that does not have a value for that key, then null will be 64 * in the set. This can be use to categorize books that don't have that key. 65 * For example, "Language" will return all the languages for this 66 * BookMetaDataList and null for which the language is unknown. 67 * 68 * @param key the property key 69 * @return the values for a particular key. 70 */ 71 public Set<Object> getGroup(String key) { 72 Set<Object> results = new TreeSet<Object>(); 73 for (Book book : this) { 74 Object property = book.getProperty(key); 75 if (property != null) { 76 results.add(property); 77 } 78 } 79 return results; 80 } 81 82 public BookSet filter(String key, Object value) { 83 return filter(new GroupFilter(key, value)); 84 } 85 86 /** 87 * Get a set of books that satisfy the condition imposed by the filter. 88 * 89 * @param filter the condition on which to select books 90 * @return the set of matching books 91 */ 92 public BookSet filter(Filter<Book> filter) { 93 // create a copy of the list and 94 // remove everything that fails the test. 95 BookSet listSet = (BookSet) clone(); 96 Iterator<Book> iter = listSet.iterator(); 97 while (iter.hasNext()) { 98 Book obj = iter.next(); 99 if (!filter.test(obj)) { 100 iter.remove(); 101 } 102 } 103 return listSet; 104 } 105 106 /* (non-Javadoc) 107 * @see java.util.ArrayList#add(int, java.lang.Object) 108 */ 109 @Override 110 public void add(int index, Book element) { 111 // ignore the requested index 112 add(element); 113 } 114 115 /* (non-Javadoc) 116 * @see java.util.ArrayList#add(java.lang.Object) 117 */ 118 @Override 119 public final boolean add(Book book) { 120 // Add the item only if it is not in the list. 121 // Add it into the list so that it is in sorted order. 122 int pos = Collections.binarySearch(this, book); 123 if (pos < 0) { 124 super.add(-pos - 1, book); 125 return true; 126 } 127 return false; 128 } 129 130 /* (non-Javadoc) 131 * @see java.util.ArrayList#addAll(java.util.Collection) 132 */ 133 @Override 134 public final boolean addAll(Collection<? extends Book> c) { 135 // Might be better to add the list to the end 136 // and then sort the list. 137 // This can be revisited if the list performs badly. 138 boolean added = false; 139 for (Book book : c) { 140 if (add(book)) { 141 added = true; 142 } 143 } 144 return added; 145 } 146 147 /* (non-Javadoc) 148 * @see java.util.ArrayList#addAll(int, java.util.Collection) 149 */ 150 @Override 151 public final boolean addAll(int index, Collection<? extends Book> c) { 152 // Ignore the index 153 return addAll(c); 154 } 155 156 /* (non-Javadoc) 157 * @see java.util.ArrayList#set(int, java.lang.Object) 158 */ 159 @Override 160 public Book set(int index, Book element) { 161 // remove the item at the index (keep it to return it), 162 // then insert the item into the sorted list. 163 Book item = remove(index); 164 add(element); 165 return item; 166 } 167 168 /** 169 * GroupFilter does the SQL traditional group by. 170 */ 171 private static final class GroupFilter implements Filter<Book> { 172 GroupFilter(String aKey, Object aValue) { 173 key = aKey; 174 value = aValue; 175 } 176 177 public boolean test(Book book) { 178 String property = book.getProperty(key); 179 return property != null && property.equals(value); 180 } 181 182 private String key; 183 private Object value; 184 } 185 186 /** 187 * Serialization ID 188 */ 189 private static final long serialVersionUID = 3258688806185154867L; 190 191 } 192