1   /**
2    * Distribution License:
3    * BibleDesktop is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU General Public License, version 2 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/gpl.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   * Copyright: 2005
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: WholeBibleTreeNode.java 2230 2012-02-08 00:00:10Z dmsmith $
21   */
22  package org.crosswire.bibledesktop.passage;
23  
24  import java.util.Enumeration;
25  
26  import javax.swing.tree.TreeNode;
27  
28  import org.crosswire.bibledesktop.BDMsg;
29  import org.crosswire.common.icu.NumberShaper;
30  import org.crosswire.jsword.passage.Verse;
31  import org.crosswire.jsword.passage.VerseRange;
32  import org.crosswire.jsword.versification.BibleBook;
33  import org.crosswire.jsword.versification.Versification;
34  import org.crosswire.jsword.versification.system.Versifications;
35  
36  /**
37   * A PassageTreeNode extends TreeNode to Model a Passage.
38   * 
39   * @see gnu.gpl.License for license details.<br>
40   *      The copyright to this program is held by it's authors.
41   * @author Joe Walker [joe at eireneh dot com]
42   */
43  public final class WholeBibleTreeNode implements TreeNode {
44      /**
45       * The start point for all WholeBibleTreeNodes.
46       */
47      public static WholeBibleTreeNode getRootNode() {
48          // AV11N(DMS): Is this right?
49          Versification v11n = Versifications.instance().getDefaultVersification();
50          return new WholeBibleTreeNode(null, v11n.getAllVerses(), Level.BIBLE);
51      }
52  
53      /**
54       * We could do some caching here if needs be.
55       */
56      protected static WholeBibleTreeNode getNode(TreeNode parent, BibleBook b, int c, int v) {
57          // AV11N(DMS): Is this right?
58          Versification v11n = Versifications.instance().getDefaultVersification();
59          Verse start = null;
60          Verse end = null;
61          Level thislevel = Level.BOOK;
62  
63          if (b == null) {
64              assert false : "BibleBook is null";
65          } else if (c == -1) {
66              thislevel = Level.BOOK;
67              int ec = v11n.getLastChapter(b);
68              int ev = v11n.getLastVerse(b, ec);
69              start = new Verse(b, 0, 0);
70              end = new Verse(b, ec, ev);
71          } else if (v == -1) {
72              thislevel = Level.CHAPTER;
73              int ev = v11n.getLastVerse(b, c);
74              start = new Verse(b, c, 0);
75              end = new Verse(b, c, ev);
76          } else {
77              thislevel = Level.VERSE;
78              start = new Verse(b, c, v);
79              end = start;
80          }
81  
82          VerseRange rng = new VerseRange(v11n, start, end);
83          return new WholeBibleTreeNode(parent, rng, thislevel);
84      }
85  
86      /**
87       * This constructor is for when we are really a BookTreeNode
88       */
89      private WholeBibleTreeNode(TreeNode parent, VerseRange range, Level level) {
90          if (parent != null) {
91              this.parent = parent;
92          } else {
93              this.parent = this;
94          }
95  
96          this.range = range;
97          this.level = level;
98          shaper = new NumberShaper();
99      }
100 
101     /**
102      * The current Passage number
103      */
104     public VerseRange getVerseRange() {
105         return range;
106     }
107 
108     /**
109      * @see javax.swing.tree.TreeNode#getParent()
110      */
111     public TreeNode getParent() {
112         return parent;
113     }
114 
115     /**
116      * @see javax.swing.tree.TreeNode#getAllowsChildren()
117      */
118     public boolean getAllowsChildren() {
119         return level != Level.VERSE;
120     }
121 
122     /**
123      * @see javax.swing.tree.TreeNode#isLeaf()
124      */
125     public boolean isLeaf() {
126         return level == Level.VERSE;
127     }
128 
129     /**
130      * How we appear in the Tree
131      */
132     @Override
133     public String toString() {
134         switch (level) {
135         case BIBLE:
136             // TRANSLATOR: The top level of the tree of Bible books, chapters and verses.
137             return BDMsg.gettext("The Bible");
138 
139         case BOOK:
140             return range.getStart().getBook().getPreferredName();
141 
142         case CHAPTER:
143             return shaper.shape(Integer.toString(range.getStart().getChapter()));
144 
145         case VERSE:
146             return shaper.shape(Integer.toString(range.getStart().getVerse()));
147 
148         default:
149             // TRANSLATOR: Unexpected error condition.
150             return BDMsg.gettext("Error");
151         }
152     }
153 
154     /**
155      * Returns the child <code>TreeNode</code> at index i
156      */
157     public TreeNode getChildAt(int i) {
158         switch (level) {
159         case BIBLE:
160             return WholeBibleTreeNode.getNode(this, rs.getBooks().getBook(i), -1, -1);
161 
162         case BOOK:
163             return WholeBibleTreeNode.getNode(this, range.getStart().getBook(), i, -1);
164 
165         case CHAPTER:
166             return WholeBibleTreeNode.getNode(this, range.getStart().getBook(), range.getStart().getChapter(), i);
167 
168         default:
169             return null;
170         }
171     }
172 
173     /**
174      * Returns the number of children <code>TreeNode</code>s the receiver
175      * contains.
176      */
177     public int getChildCount() {
178         switch (level) {
179         case BIBLE:
180             return rs.getBooks().getBookCount();
181 
182         case BOOK:
183             return rs.getLastChapter(range.getStart().getBook()) + 1;
184 
185         case CHAPTER:
186             return rs.getLastVerse(range.getStart().getBook(), range.getStart().getChapter()) + 1;
187 
188         default:
189             return 0;
190         }
191     }
192 
193     /**
194      * Returns the index of <code>node</code> in the receivers children. If the
195      * receiver does not contain <code>node</code>, 0 will be returned.
196      */
197     public int getIndex(TreeNode node) {
198         if (!(node instanceof WholeBibleTreeNode)) {
199             return 0;
200         }
201 
202         WholeBibleTreeNode vnode = (WholeBibleTreeNode) node;
203 
204         switch (level) {
205         case BIBLE:
206             // AV11N(DMS): need to get ordinal from the BibleBookList
207             return vnode.getVerseRange().getStart().getBook().ordinal();
208 
209         case BOOK:
210             return vnode.getVerseRange().getStart().getChapter();
211 
212         case CHAPTER:
213             return vnode.getVerseRange().getStart().getVerse();
214 
215         default:
216             return 0;
217         }
218     }
219 
220     /**
221      * @see javax.swing.tree.TreeNode#children()
222      */
223     public Enumeration<TreeNode> children() {
224         return new WholeBibleEnumeration(this);
225     }
226 
227     /**
228      * Iterate over the Books
229      */
230     private class WholeBibleEnumeration implements Enumeration<TreeNode> {
231         public WholeBibleEnumeration(WholeBibleTreeNode treeNode) {
232             this.treeNode = treeNode;
233         }
234         public boolean hasMoreElements() {
235             return count < treeNode.getChildCount();
236         }
237 
238         public TreeNode nextElement() {
239             count++;
240             return treeNode.getChildAt(count);
241         }
242 
243         private WholeBibleTreeNode treeNode;
244         private int count;
245     }
246 
247     /**
248      * Levels at which this node stands.
249      */
250     private enum Level {
251         BIBLE,
252         BOOK,
253         CHAPTER,
254         VERSE,
255     }
256 
257     // AV11N(DMS): Is this right?
258     private Versification rs = Versifications.instance().getDefaultVersification();
259 
260     /** Change the number representation as needed */
261     private NumberShaper shaper;
262 
263     /** The range that this node refers to */
264     private VerseRange range;
265 
266     /** Our parent tree node */
267     private TreeNode parent;
268 
269     /** The level of this node one of: LEVEL_[BIBLE|BOOK|CHAPTER|VERSE] */
270     private Level level;
271 }
272