001 /* PAVLOV -- Multiple Choice Study System 002 * Copyright (C) 2000 - 2004 T.J. Willis 003 * 004 * This program is free software; you can redistribute it and/or 005 * modify it under the terms of the GNU General Public License 006 * as published by the Free Software Foundation; either version 2 007 * of the License, or (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program; if not, write to the Free Software 016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 017 * 018 * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/library/Chapter.java,v 1.7 2004/07/01 05:50:20 tj_willis Exp $ 019 */ 020 package net.sourceforge.pavlov.library; 021 import java.util.*; 022 import java.io.*; 023 import org.apache.log4j.*; 024 025 /** 026 * Describes a chapter, which contains questions. 027 * 028 * @author <a href="mailto:tj_willis@users.sourceforge.net"></a> 029 * @version 1.0 030 * @see Question 031 * @see Book 032 * @see Library 033 * @has 1 Has 1..n net.sourceforge.pavlov.library.Question 034 */ 035 public final class Chapter extends LibraryDocument 036 implements AbstractChapter, Serializable, Comparable { 037 /** Filename for a descriptive image. */ 038 private String coverFile; 039 /** Holds the questions, keyed off of Question.id */ 040 private TreeMap<String,Question> questions; 041 042 /** Creates an untitled chapter. */ 043 public Chapter() { 044 this("Untitled"); 045 } 046 047 private void init(){ 048 questions = new TreeMap<String, Question>(); 049 } 050 051 /** 052 * Creates a new <code>Chapter</code> instance. 053 * 054 * @param newName a <code>String</code> value 055 */ 056 public Chapter(String newName){ 057 setName(newName); 058 init(); 059 } 060 061 /** 062 * Gets the question with the specified ID or null if it doesn't exist. 063 * @param id a <code>String</code> value 064 * @return a <code>Question</code> value 065 */ 066 public Question getQuestion(final String id) { 067 return questions.get(id); 068 } 069 070 public int compareTo(Object obj){ 071 Chapter c = (Chapter)obj; 072 return getName().compareTo(c.getName()); 073 } 074 075 /** 076 * Describe <code>setQuestions</code> method here. 077 * 078 */ 079 public void setQuestions(Collection<Question> list) { 080 questions.clear(); 081 for(Question da : list) { 082 if(da==null) continue; 083 addQuestion(da); 084 } 085 } 086 087 /** 088 * Number of questions this chapter contains. 089 * @return an <code>int</code> value 090 */ 091 public int getNumberOfQuestions() { 092 return questions.size(); 093 } 094 095 /** 096 * Returns the title of this chapter. 097 * @return a <code>String</code> value 098 * @deprecated Use getName() 099 */ 100 @Deprecated public String getTitle() { 101 return getName(); 102 } 103 104 /** 105 * Sets the title of this chapter. 106 * @param n a <code>String</code> value 107 * @deprecated Use setTitle() 108 */ 109 @Deprecated public void setTitle(String n) { 110 setName(n); 111 } 112 113 /** 114 * Returns the filename for a descriptive image. 115 * @return a <code>String</code> value 116 */ 117 public String getCover() { 118 return coverFile; 119 } 120 121 /** 122 * Sets the filename for a descriptive image. 123 * @param n a <code>String</code> value 124 */ 125 public void setCover(String n) { 126 coverFile = n; 127 } 128 129 /** 130 * Adds a question using it's ID as the key 131 * @param b a <code>Question</code> value 132 */ 133 public void addQuestion(Question b) { 134 questions.put(b.getID(), b); 135 } 136 137 /** 138 * Dumps the chapter in XML format to the 139 * given writer. Dumps all questions too. 140 * @param writer a <code>java.io.Writer</code> value 141 * @exception java.io.IOException if an error occurs 142 */ 143 public void toXML(java.io.Writer writer) 144 throws java.io.IOException { 145 Collection<Question> v = getQuestionsCollection(); 146 147 writer.write("\t\t<CHAPTER NAME=\"" + getName() + "\" AUTHOR=\"" + author + "\" COVER=\"" + coverFile + "\">\n"); 148 writer.write("\t\t<TOPICS>" + description + "</TOPICS>\n"); 149 150 for(Question da : v) { 151 da.toXML(writer); 152 } 153 writer.write("\t\t</CHAPTER>\n"); 154 } 155 156 /** 157 * Returns all questions as a Collection 158 * @return a <code>Collection</code> value 159 * @deprecated 160 */ 161 @Deprecated public Collection<Question> getQuestionsCollection() { 162 return questions.values(); 163 } 164 165 /** 166 * Returns the chapter's questions as a read-only collection. 167 * @return a <code>Collection</code> value 168 */ 169 public Collection<Question> getQuestionsReadOnly(){ 170 return Collections.unmodifiableCollection(getQuestionsCollection()); 171 } 172 173 /** 174 * Describe <code>getQuestions</code> method here. 175 * 176 * @return a <code>Hashtable</code> value 177 */ 178 public TreeMap<String, Question> getQuestions(){ 179 return questions; 180 } 181 182 /** 183 * Returns the chapter's title 184 * @return a <code>String</code> value 185 */ 186 public String toString() { 187 return getName(); 188 } 189 190 /** 191 * Describe <code>makeBlankChapter</code> method here. 192 * 193 * @return a <code>Chapter</code> value 194 */ 195 public static Chapter makeBlankChapter() 196 { 197 Chapter n = new Chapter(); 198 n.setAuthor("Unknown"); 199 n.setTitle("Unknown"); 200 n.setCover("Unknown"); 201 n.setCover("No description"); 202 Question q = Question.makeBlankQuestion(); 203 n.addQuestion(q.deepCopy()); 204 return n; 205 } 206 207 /** 208 * Returns true if the given object is a chapter and all its elements 209 * are equal to mine. 210 * 211 * @param obj an <code>Object</code> value 212 * @return a <code>boolean</code> value 213 */ 214 public boolean equals(Object obj) 215 { 216 if(obj==null && this!=null) return false; 217 if(obj!=null && this==null) return false; 218 if(obj==null && this==null) return true; 219 220 if( !(obj instanceof Chapter) ) return false; 221 Chapter q = (Chapter) obj; 222 223 if(getAuthor() == null && q.getAuthor() !=null) return false; 224 if(getName() == null && q.getName() !=null) return false; 225 if(getCover()== null && q.getCover() !=null) return false; 226 if(getDescription() == null && q.getDescription() !=null) return false; 227 if(getQuestions() == null && q.getQuestions() !=null) return false; 228 229 // FIXED: these should be .equals() 230 // whee... my first bug caught by JUnit! :) 231 if(getAuthor()!=null) 232 if( !getAuthor().equals(q.getAuthor())) return false; 233 if(getName()!=null) 234 if( !getName().equals(q.getName())) return false; 235 if(getCover()!=null) 236 if( !getCover().equals(q.getCover())) return false; 237 if(getDescription()!=null) 238 if( !getDescription().equals(q.getDescription())) return false; 239 if(getQuestions()!=null) 240 if( !getQuestions().equals(q.getQuestions())) return false; 241 242 return true; 243 } 244 245 246 /** 247 * Uses a nifty trick from "Design Patterns in Java" to make a 248 * completely independent copy of this chapter. Useful in chapter 249 * editors. 250 * 251 * @return a <code>Chapter</code> value 252 */ 253 public Chapter deepCopy() 254 { 255 try { 256 ByteArrayOutputStream b = new ByteArrayOutputStream(); 257 ObjectOutputStream out = new ObjectOutputStream(b); 258 out.writeObject(this); 259 ByteArrayInputStream bIn = new ByteArrayInputStream(b.toByteArray()); 260 ObjectInputStream oi = new ObjectInputStream(bIn); 261 return ( (Chapter)oi.readObject()); 262 } catch (IOException e) { 263 return null; 264 } catch (ClassNotFoundException e1){ 265 return null; 266 } 267 } 268 269 270 } 271