| 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