KwBibleModule::createKey: pass on bool* valid
[kworship.git] / kworship / bible / KwBibleModule.cpp
blob30873c5471ae4c8aa837b810cab99dfbb9e5fa64
1 /***************************************************************************
2 * This file is part of KWorship. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
4 * *
5 * KWorship is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * KWorship is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with KWorship. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
20 /**
21 * @file KwBibleModule.cpp
22 * @brief An abstract bible module (analagous to a SWORD module).
23 * @author James Hogan <james@albanarts.com>
26 #include "KwBibleModule.h"
27 #include "KwBiblePassage.h"
29 #include <QRegExp>
32 * Constructors + destructor
35 /// Default constructor.
36 KwBibleModule::KwBibleModule()
37 : m_books()
38 , m_rightToLeft(false)
42 /// Destructor.
43 KwBibleModule::~KwBibleModule()
48 * Main interface
51 /// Create a key from a string.
52 KwBibleModule::Key KwBibleModule::createKey(const QString& text, bool* valid)
54 // Find the key relative to the first chapter of the first book.
55 return createKey(createKey(0, 0), text, valid);
58 /// Create a key from a string relative to another key.
59 KwBibleModule::Key KwBibleModule::createKey(const Key& other, const QString& text, bool* valid)
61 Key key = other;
62 static QRegExp re("^\\s*" // Must from beginning (ignore whitespace)
63 // 1( 2( 3() 4() ) )
64 "(((\\S+)|\"([^\"]+)\")\\s+)?" // Optional book name followed by spaces
65 // 5( 6() )
66 "((\\d+)[:.])?" // Optional chapter number followed by [:.]
67 // 7()
68 "(\\d+)?" // Optional verse number
69 // 8(
70 "(\\s*-\\s*" // Optionally start matching dash followed by end of the range
71 // 9( 10() )
72 "((\\d+)[:.])?" // Optional chapter number followed by [:.]
73 // 11()
74 "(\\d+)?" // Optional verse number
75 // )
76 ")?" // End of matching end of range
77 "\\s*$" // Must match to end (ignore whitespace)
79 Q_ASSERT(re.isValid());
80 bool isValid = true;
81 if (re.exactMatch(text))
83 QStringList cap = re.capturedTexts();
84 // Get book name
85 QString bookName;
86 if (!cap[3].isEmpty())
88 bookName = cap[3];
90 else if (!cap[4].isEmpty())
92 bookName = cap[4];
94 if (!bookName.isEmpty())
96 int book = bookIndex(bookName);
97 if (book >= 0)
99 key.start.book = book;
101 else
103 isValid = false;
106 // Get chapter
107 QString chapterName = cap[6];
108 if (!chapterName.isEmpty())
110 int chapter = chapterName.toInt() - 1;
111 if (chapter >= 0 && chapter < numChapters(key.start.book))
113 key.start.chapter = chapter;
115 else
117 isValid = false;
120 // Get verse
121 QString verseName = cap[7];
122 if (!verseName.isEmpty())
124 int verse = verseName.toInt() - 1;
125 if (verse >= 0 && verse < numVerses(key.start.book, key.start.chapter))
127 key.start.verse = verse;
129 else
131 isValid = false;
134 // End of range
135 if (!cap[8].isEmpty())
137 key.end.book = key.start.book;
138 key.end.chapter = key.start.chapter;
139 key.end.verse = -1;
140 // Get chapter
141 QString chapterName = cap[10];
142 if (!chapterName.isEmpty())
144 int chapter = chapterName.toInt() - 1;
145 if (chapter >= 0 && chapter < numChapters(key.start.book))
147 key.end.chapter = chapter;
149 else
151 isValid = false;
154 // Get verse
155 QString verseName = cap[11];
156 if (!verseName.isEmpty())
158 int verse = verseName.toInt() - 1;
159 if (verse >= 0 && verse < numVerses(key.start.book, key.start.chapter))
161 key.end.verse = verse;
163 else
165 isValid = false;
168 if (key.end.verse < 0)
170 key.end.verse = numVerses(key.end.book, key.end.chapter)-1;
174 else
176 isValid = false;
178 //std::cout << "result: " << key.start.book << "." << key.start.chapter << ":" << key.start.verse << " - "
179 // << key.end.book << "." << key.end.chapter << ":" << key.end.verse << std::endl;
180 if (0 != valid)
182 *valid = isValid;
184 return key;
187 /// Create a key from individual values.
188 KwBibleModule::Key KwBibleModule::createKey(int book, int chapter, int verse)
190 Key key = { { book, chapter, verse },
191 { -1, -1, -1 } };
192 return key;
195 /// Create a key from individual values.
196 KwBibleModule::Key KwBibleModule::createKey(const QString& book, int chapter, int verse)
198 int bookId = bookIndex(book);
199 Key key = { { bookId, chapter, verse },
200 { -1, -1, -1 } };
201 return key;
204 /// Create a range key between two verses in the same chapter.
205 KwBibleModule::Key KwBibleModule::createKey(const QString& book, int chapter, int verseStart,
206 int verseEnd)
208 int bookId = bookIndex(book);
209 Key key = { { bookId, chapter, verseStart },
210 { bookId, chapter, verseEnd } };
211 return key;
214 /// Create a range key between two verses in different chapters.
215 KwBibleModule::Key KwBibleModule::createKey(const QString& book, int chapterStart, int verseStart,
216 int chapterEnd, int verseEnd)
218 int bookId = bookIndex(book);
219 Key key = { { bookId, chapterStart, verseStart },
220 { bookId, chapterEnd, verseEnd } };
221 return key;
224 /// Create a range key between two verses in different books.
225 KwBibleModule::Key KwBibleModule::createKey(const QString& bookStart, int chapterStart, int verseStart,
226 const QString& bookEnd, int chapterEnd, int verseEnd)
228 int bookIdStart = bookIndex(bookStart);
229 int bookIdEnd = bookIndex(bookEnd);
230 Key key = { { bookIdStart, chapterStart, verseStart },
231 { bookIdEnd, chapterEnd, verseEnd } };
232 return key;
235 /// Is the text right to left?
236 bool KwBibleModule::isRightToLeft() const
238 return m_rightToLeft;
241 /// List the books in this module.
242 const QStringList& KwBibleModule::books()
244 if (m_books.isEmpty())
246 obtainBooks();
248 return m_books;
251 /// Get the index of a book from it's name.
252 int KwBibleModule::bookIndex(const QString& name)
254 if (m_books.isEmpty())
256 obtainBooks();
258 return m_books.indexOf(name);
261 /// Get the name of a book from it's index.
262 QString KwBibleModule::bookName(int book)
264 if (m_books.isEmpty())
266 obtainBooks();
268 if (book >= 0 && book < m_books.size())
270 return m_books[book];
272 else
274 return QString();
278 bool KwBibleModule::fillPassage(const Key& key, KwBiblePassage* outPassage)
280 Key range = key;
282 // Complete the range
283 if (range.start.book < 0)
285 // Start book must be specified
286 return false;
288 else if (range.end.book < 0)
290 range.end.book = range.start.book;
293 if (range.start.chapter < 0)
295 range.start.chapter = 0;
296 range.end.chapter = numChapters(range.end.book)-1;
298 else if (range.end.chapter < 0)
300 range.end.chapter = range.start.chapter;
303 if (range.start.verse < 0)
305 range.start.verse = 0;
306 range.end.verse = numVerses(range.end.book, range.end.chapter)-1;
308 else if (range.end.verse < 0)
310 range.end.verse = range.start.verse;
313 outPassage->setSource(managerId(), name(), m_rightToLeft);
314 outPassage->initBooks(range.start.book, 1+range.end.book-range.start.book);
315 for (int book = range.start.book; book <= range.end.book; ++book)
317 bool isFirstBook = (book == range.start.book);
318 bool isLastBook = (book == range.end.book);
319 int maxChapters = numChapters(book);
320 int firstChapter = (isFirstBook ? range.start.chapter : 0);
321 int lastChapter = (isLastBook ? range.end.chapter : maxChapters-1);
322 Q_ASSERT(lastChapter >= firstChapter && lastChapter < maxChapters);
323 outPassage->initBook(book, bookName(book), 1+firstChapter, 1+lastChapter-firstChapter);
324 for (int chapter = firstChapter; chapter <= lastChapter; ++chapter)
326 bool isFirstChapter = isFirstBook && (chapter == firstChapter);
327 bool isLastChapter = isLastBook && (chapter == lastChapter);
328 int maxVerses = numVerses(book, chapter);
329 int firstVerse = (isFirstChapter ? range.start.verse : 0);
330 int lastVerse = (isLastChapter ? range.end.verse : maxVerses-1);
331 Q_ASSERT(lastVerse >= firstVerse && lastVerse < maxVerses);
332 outPassage->initChapter(book, 1+chapter, 1+firstVerse, 1+lastVerse-firstVerse);
333 for (int verse = firstVerse; verse <= lastVerse; ++verse)
335 fillPassageVerse(book, chapter, verse, outPassage);
339 return true;
343 * Protected virtual interface
346 /// Ensure that the book list is up to date.
347 void KwBibleModule::obtainBooks()
352 * Protected interface
355 /// Update the list of books.
356 void KwBibleModule::setBooks(const QStringList& books)
358 m_books = books;
361 /// Set whether the module has text right-to-left.
362 void KwBibleModule::setRightToLeft(bool rightToLeft)
364 m_rightToLeft = rightToLeft;