Passage.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.passage; 21 22 import java.io.IOException; 23 import java.io.Reader; 24 import java.io.Writer; 25 import java.util.Iterator; 26 27 /** 28 * A Passage is a specialized Collection of Verses. The additions are: 29 * <ul> 30 * <li>List blurring 31 * <li>Range Counting and iteration (in addition to Verse counting etc) 32 * <li>List change notification, so you can register to update yourself, and 33 * this goes hand in hand with a added thread-safe contract. 34 * <li>getName() to be more VerseBase like. 35 * <li>Human readable serialization. So we can read and write to and from OLB 36 * style Passage files. 37 * </ul> 38 * 39 * <p> 40 * Passage no longer extends the Collection interface to avoid J2SE 1.1/1.2 41 * portability problems, and because many of the things that a Passage does rely 42 * on consecutive Verses which are an alien concept to Collections. So users 43 * would have to use the Passage interface anyway. 44 * 45 * <p> 46 * Other arguments for and against. 47 * <ul> 48 * <li>The generic version will postpone some type errors to runtime. Is this a 49 * huge problem? Are there many syntax errors that would be lost? Probably not. 50 * <li>The specific version would stop enhancements like add("Gen 1:1"); (But 51 * this is just syntactical sugar anyway). 52 * <li>The specific version allows functionality by is-a as well as has-a. But a 53 * Passage is fundamentally different so this is not that much use. 54 * <li>At the end of the day I expect people to use getName() instead of 55 * toString() and blur(), both of which are Passage things not Collection 56 * things. So the general use of these classes is via a Passage interface not a 57 * Collections one. 58 * <li>Note that the implementations of Passage could not adhere strictly to the 59 * Collections interface in returning false from add(), remove() etc, to specify 60 * if the Collection was changed. Given ranges and the like this can get very 61 * time consuming and complex. 62 * </ul> 63 * 64 * <p> 65 * The upshot of all this is that I am removing the Collections interface from 66 * Passage. 67 * 68 * <p> 69 * I considered giving Passages names to allow for a CLI that could use named 70 * RangedPassages, however that is perhaps better left to another class. 71 * 72 * @see gnu.lgpl.License The GNU Lesser General Public License for details. 73 * @author Joe Walker 74 */ 75 public interface Passage extends VerseKey<Passage> { 76 /** 77 * A summary of the verses in this Passage For example 78 * "10 verses in 4 books" 79 * 80 * @return a String containing an overview of the verses 81 */ 82 String getOverview(); 83 84 /** 85 * Returns the number of verses in this collection. Like Collection.size() 86 * This does not mean the Passage needs to use Verses, just that it 87 * understands the concept. 88 * 89 * @return the number of Verses in this collection 90 * @see Verse 91 */ 92 int countVerses(); 93 94 /** 95 * Determine whether there are two or more ranges. 96 * 97 * @param restrict 98 * Do we break ranges at chapter/book boundaries 99 * @return whether there are two or more ranges 100 * @see VerseRange 101 */ 102 boolean hasRanges(RestrictionType restrict); 103 104 /** 105 * Like countVerses() that counts VerseRanges instead of Verses Returns the 106 * number of fragments in this collection. This does not mean the Passage 107 * needs to use VerseRanges, just that it understands the concept. 108 * 109 * @param restrict 110 * Do we break ranges at chapter/book boundaries 111 * @return the number of VerseRanges in this collection 112 * @see VerseRange 113 */ 114 int countRanges(RestrictionType restrict); 115 116 /** 117 * Ensures that there are a maximum of <code>count</code> Verses in this 118 * Passage. If there were more than <code>count</code> Verses then a new 119 * Passage is created containing the Verses from <code>count</code>+1 120 * onwards. If there was not greater than <code>count</code> in the Passage, 121 * then the passage remains unchanged, and null is returned. 122 * 123 * @param count 124 * The maximum number of Verses to allow in this collection 125 * @return A new Passage containing the remaining verses or null 126 * @see Verse 127 */ 128 Passage trimVerses(int count); 129 130 /** 131 * Ensures that there are a maximum of <code>count</code> VerseRanges in 132 * this Passage. If there were more than <code>count</code> VerseRanges then 133 * a new Passage is created containing the VerseRanges from 134 * <code>count</code>+1 onwards. If there was not greater than 135 * <code>count</code> in the Passage, then the passage remains unchanged, 136 * and null is returned. 137 * 138 * @param count 139 * The maximum number of VerseRanges to allow in this collection 140 * @param restrict 141 * Do we break ranges at chapter/book boundaries 142 * @return A new Passage containing the remaining verses or null 143 * @see VerseRange 144 */ 145 Passage trimRanges(int count, RestrictionType restrict); 146 147 /** 148 * How many books are there in this Passage 149 * 150 * @return The number of distinct books 151 */ 152 int booksInPassage(); 153 154 /** 155 * Get a specific Verse from this collection 156 * 157 * @param offset 158 * The verse offset (legal values are 0 to countVerses()-1) 159 * @return The Verse 160 * @throws ArrayIndexOutOfBoundsException 161 * If the offset is out of range 162 */ 163 Verse getVerseAt(int offset) throws ArrayIndexOutOfBoundsException; 164 165 /** 166 * Get a specific VerseRange from this collection 167 * 168 * @param offset 169 * The verse range offset (legal values are 0 to countRanges()-1) 170 * @param restrict 171 * Do we break ranges at chapter/book boundaries 172 * @return The Verse Range 173 * @throws ArrayIndexOutOfBoundsException 174 * If the offset is out of range 175 */ 176 VerseRange getRangeAt(int offset, RestrictionType restrict) throws ArrayIndexOutOfBoundsException; 177 178 /** 179 * Like iterator() that iterates over VerseRanges instead of Verses. 180 * Exactly the same data will be traversed, however using rangeIterator() 181 * will usually give fewer iterations (and never more) 182 * 183 * @param restrict 184 * Do we break ranges over chapters 185 * @return A list enumerator 186 */ 187 Iterator<VerseRange> rangeIterator(RestrictionType restrict); 188 189 /** 190 * Returns true if this collection contains all the specified Verse 191 * 192 * @param that 193 * Verse or VerseRange that may exist in this Passage 194 * @return true if this collection contains that 195 */ 196 boolean contains(Key that); 197 198 /** 199 * Add this Verse/VerseRange to this Passage 200 * 201 * @param that 202 * The Verses to be added from this Passage 203 */ 204 void add(Key that); 205 206 /** 207 * Remove this Verse/VerseRange from this Passage 208 * 209 * @param that 210 * The Verses to be removed from this Passage 211 */ 212 void remove(Key that); 213 214 /** 215 * Returns true if this Passage contains all of the verses in that Passage 216 * 217 * @param that 218 * Passage to be checked for containment in this collection. 219 * @return true if this reference contains all of the Verses in that Passage 220 */ 221 boolean containsAll(Passage that); 222 223 /** 224 * To be compatible with humans we read/write ourselves to a file that a 225 * human can read and even edit. OLB verse.lst integration is a good goal 226 * here. 227 * 228 * @param in 229 * The stream to read from 230 * @exception java.io.IOException 231 * If the file/network etc breaks 232 * @exception NoSuchVerseException 233 * If the file was invalid 234 */ 235 void readDescription(Reader in) throws IOException, NoSuchVerseException; 236 237 /** 238 * To be compatible with humans we read/write ourselves to a file that a 239 * human can read and even edit. OLB verse.lst integration is a good goal 240 * here. 241 * 242 * @param out 243 * The stream to write to 244 * @exception java.io.IOException 245 * If the file/network etc breaks 246 */ 247 void writeDescription(Writer out) throws IOException; 248 249 /** 250 * For performance reasons we may well want to hint to the Passage that we 251 * have done editing it for now and that it is safe to cache certain values 252 * to speed up future reads. Any action taken by this method will be undone 253 * simply by making a future edit, and the only loss in calling 254 * optimizeReads() is a loss of time if you then persist in writing to the 255 * Passage. 256 */ 257 void optimizeReads(); 258 259 /** 260 * Event Listeners - Add Listener 261 * 262 * @param li 263 * The listener to add 264 */ 265 void addPassageListener(PassageListener li); 266 267 /** 268 * Event Listeners - Remove Listener 269 * 270 * @param li 271 * The listener to remove 272 */ 273 void removePassageListener(PassageListener li); 274 } 275