diff options
Diffstat (limited to 'fbreader/src/bookmodel')
-rw-r--r-- | fbreader/src/bookmodel/BookModel.cpp | 68 | ||||
-rw-r--r-- | fbreader/src/bookmodel/BookModel.h | 91 | ||||
-rw-r--r-- | fbreader/src/bookmodel/BookReader.cpp | 303 | ||||
-rw-r--r-- | fbreader/src/bookmodel/BookReader.h | 114 | ||||
-rw-r--r-- | fbreader/src/bookmodel/FBHyperlinkType.h | 30 | ||||
-rw-r--r-- | fbreader/src/bookmodel/FBTextKind.h | 70 |
6 files changed, 676 insertions, 0 deletions
diff --git a/fbreader/src/bookmodel/BookModel.cpp b/fbreader/src/bookmodel/BookModel.cpp new file mode 100644 index 0000000..2123282 --- /dev/null +++ b/fbreader/src/bookmodel/BookModel.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <ZLImage.h> +#include <ZLFile.h> + +#include "BookModel.h" +#include "BookReader.h" + +#include "../formats/FormatPlugin.h" +#include "../library/Book.h" + +BookModel::BookModel(const shared_ptr<Book> book) : myBook(book) { + myBookTextModel = new ZLTextPlainModel(book->language(), 102400); + myContentsModel = new ContentsModel(book->language()); + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(book->file(), false); + if (!plugin.isNull()) { + plugin->readModel(*this); + } +} + +BookModel::~BookModel() { +} + +void BookModel::setHyperlinkMatcher(shared_ptr<HyperlinkMatcher> matcher) { + myHyperlinkMatcher = matcher; +} + +BookModel::Label BookModel::label(const std::string &id) const { + if (!myHyperlinkMatcher.isNull()) { + return myHyperlinkMatcher->match(myInternalHyperlinks, id); + } + + std::map<std::string,Label>::const_iterator it = myInternalHyperlinks.find(id); + return (it != myInternalHyperlinks.end()) ? it->second : Label(0, -1); +} + +ContentsModel::ContentsModel(const std::string &language) : ZLTextTreeModel(language) { +} + +void ContentsModel::setReference(const ZLTextTreeParagraph *paragraph, int reference) { + myReferenceByParagraph[paragraph] = reference; +} + +int ContentsModel::reference(const ZLTextTreeParagraph *paragraph) const { + std::map<const ZLTextTreeParagraph*,int>::const_iterator it = myReferenceByParagraph.find(paragraph); + return (it != myReferenceByParagraph.end()) ? it->second : -1; +} + +const shared_ptr<Book> BookModel::book() const { + return myBook; +} diff --git a/fbreader/src/bookmodel/BookModel.h b/fbreader/src/bookmodel/BookModel.h new file mode 100644 index 0000000..6f83728 --- /dev/null +++ b/fbreader/src/bookmodel/BookModel.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __BOOKMODEL_H__ +#define __BOOKMODEL_H__ + +#include <map> +#include <string> + +#include <ZLTextModel.h> +#include <ZLTextParagraph.h> +#include <ZLUserData.h> + +class ZLImage; +class Book; + +class ContentsModel : public ZLTextTreeModel { + +public: + ContentsModel(const std::string &language); + void setReference(const ZLTextTreeParagraph *paragraph, int reference); + int reference(const ZLTextTreeParagraph *paragraph) const; + +private: + std::map<const ZLTextTreeParagraph*,int> myReferenceByParagraph; +}; + +class BookModel : public ZLUserDataHolder { + +public: + struct Label { + Label(shared_ptr<ZLTextModel> model, int paragraphNumber) : Model(model), ParagraphNumber(paragraphNumber) {} + + const shared_ptr<ZLTextModel> Model; + const int ParagraphNumber; + }; + +public: + class HyperlinkMatcher { + + public: + virtual Label match(const std::map<std::string,Label> &lMap, const std::string &id) const = 0; + }; + +public: + BookModel(const shared_ptr<Book> book); + ~BookModel(); + + void setHyperlinkMatcher(shared_ptr<HyperlinkMatcher> matcher); + + shared_ptr<ZLTextModel> bookTextModel() const; + shared_ptr<ZLTextModel> contentsModel() const; + + const ZLImageMap &imageMap() const; + Label label(const std::string &id) const; + + const shared_ptr<Book> book() const; + +private: + const shared_ptr<Book> myBook; + shared_ptr<ZLTextModel> myBookTextModel; + shared_ptr<ZLTextModel> myContentsModel; + ZLImageMap myImages; + std::map<std::string,shared_ptr<ZLTextModel> > myFootnotes; + std::map<std::string,Label> myInternalHyperlinks; + shared_ptr<HyperlinkMatcher> myHyperlinkMatcher; + +friend class BookReader; +}; + +inline shared_ptr<ZLTextModel> BookModel::bookTextModel() const { return myBookTextModel; } +inline shared_ptr<ZLTextModel> BookModel::contentsModel() const { return myContentsModel; } +inline const ZLImageMap &BookModel::imageMap() const { return myImages; } + +#endif /* __BOOKMODEL_H__ */ diff --git a/fbreader/src/bookmodel/BookReader.cpp b/fbreader/src/bookmodel/BookReader.cpp new file mode 100644 index 0000000..2982c43 --- /dev/null +++ b/fbreader/src/bookmodel/BookReader.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <ZLImage.h> +#include <ZLLogger.h> +#include <ZLTextStyleEntry.h> + +#include "BookReader.h" +#include "BookModel.h" + +#include "../library/Book.h" + +BookReader::BookReader(BookModel &model) : myModel(model) { + myCurrentTextModel = 0; + myLastTOCParagraphIsEmpty = false; + + myContentsParagraphExists = false; + + myInsideTitle = false; + mySectionContainsRegularContents = false; +} + +BookReader::~BookReader() { +} + +void BookReader::setMainTextModel() { + myCurrentTextModel = myModel.myBookTextModel; +} + +void BookReader::setFootnoteTextModel(const std::string &id) { + std::map<std::string,shared_ptr<ZLTextModel> >::iterator it = myModel.myFootnotes.find(id); + if (it != myModel.myFootnotes.end()) { + myCurrentTextModel = (*it).second; + } else { + myCurrentTextModel = new ZLTextPlainModel(myModel.myBookTextModel->language(), 8192); + myModel.myFootnotes.insert(std::make_pair(id, myCurrentTextModel)); + } +} + +bool BookReader::paragraphIsOpen() const { + if (myCurrentTextModel.isNull()) { + return false; + } + for (std::list<shared_ptr<ZLTextModel> >::const_iterator it = myModelsWithOpenParagraphs.begin(); it != myModelsWithOpenParagraphs.end(); ++it) { + if (*it == myCurrentTextModel) { + return true; + } + } + return false; +} + +void BookReader::unsetTextModel() { + myCurrentTextModel.reset(); +} + +void BookReader::pushKind(FBTextKind kind) { + myKindStack.push_back(kind); +} + +bool BookReader::popKind() { + if (!myKindStack.empty()) { + myKindStack.pop_back(); + return true; + } + return false; +} + +bool BookReader::isKindStackEmpty() const { + return myKindStack.empty(); +} + +void BookReader::beginParagraph(ZLTextParagraph::Kind kind) { + endParagraph(); + if (myCurrentTextModel != 0) { + ((ZLTextPlainModel&)*myCurrentTextModel).createParagraph(kind); + for (std::vector<FBTextKind>::const_iterator it = myKindStack.begin(); it != myKindStack.end(); ++it) { + myCurrentTextModel->addControl(*it, true); + } + if (!myHyperlinkReference.empty()) { + myCurrentTextModel->addHyperlinkControl(myHyperlinkKind, myHyperlinkType, myHyperlinkReference); + } + myModelsWithOpenParagraphs.push_back(myCurrentTextModel); + } +} + +void BookReader::endParagraph() { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myModelsWithOpenParagraphs.remove(myCurrentTextModel); + } +} + +void BookReader::addControl(FBTextKind kind, bool start) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addControl(kind, start); + } + if (!start && !myHyperlinkReference.empty() && (kind == myHyperlinkKind)) { + myHyperlinkReference.erase(); + } +} + +void BookReader::addStyleEntry(const ZLTextStyleEntry &entry) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addStyleEntry(entry); + } +} + +void BookReader::addStyleCloseEntry() { + addControl(REGULAR, false); //used instead in XHTMLReader + //TODO implement ZLTextModel::addStyleCloseEntry() +// if (paragraphIsOpen()) { +// flushTextBufferToParagraph(); +// myCurrentTextModel->addStyleCloseEntry(); +// } +} + +void BookReader::addFixedHSpace(unsigned char length) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addFixedHSpace(length); + } +} + +void BookReader::addHyperlinkControl(FBTextKind kind, const std::string &label) { + myHyperlinkKind = kind; + std::string type; + switch (myHyperlinkKind) { + case INTERNAL_HYPERLINK: + case FOOTNOTE: + myHyperlinkType = HYPERLINK_INTERNAL; + type = "internal"; + break; + case EXTERNAL_HYPERLINK: + myHyperlinkType = HYPERLINK_EXTERNAL; + type = "external"; + break; + case BOOK_HYPERLINK: + myHyperlinkType = HYPERLINK_BOOK; + type = "book"; + break; + default: + myHyperlinkType = HYPERLINK_NONE; + break; + } + ZLLogger::Instance().println( + "hyperlink", + " + control (" + type + "): " + label + ); + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addHyperlinkControl(kind, myHyperlinkType, label); + } + myHyperlinkReference = label; +} + +void BookReader::addHyperlinkLabel(const std::string &label) { + if (!myCurrentTextModel.isNull()) { + int paragraphNumber = myCurrentTextModel->paragraphsNumber(); + if (paragraphIsOpen()) { + --paragraphNumber; + } + addHyperlinkLabel(label, paragraphNumber); + } +} + +void BookReader::addHyperlinkLabel(const std::string &label, int paragraphNumber) { + ZLLogger::Instance().println( + "hyperlink", + " + label: " + label + ); + myModel.myInternalHyperlinks.insert(std::make_pair( + label, BookModel::Label(myCurrentTextModel, paragraphNumber) + )); +} + +void BookReader::addData(const std::string &data) { + if (!data.empty() && paragraphIsOpen()) { + if (!myInsideTitle) { + mySectionContainsRegularContents = true; + } + myBuffer.push_back(data); + } +} + +void BookReader::addContentsData(const std::string &data) { + if (!data.empty() && !myTOCStack.empty()) { + myContentsBuffer.push_back(data); + } +} + +void BookReader::flushTextBufferToParagraph() { + myCurrentTextModel->addText(myBuffer); + myBuffer.clear(); +} + +void BookReader::addImage(const std::string &id, shared_ptr<const ZLImage> image) { + myModel.myImages[id] = image; +} + +void BookReader::insertEndParagraph(ZLTextParagraph::Kind kind) { + if ((myCurrentTextModel != 0) && mySectionContainsRegularContents) { + std::size_t size = myCurrentTextModel->paragraphsNumber(); + if ((size > 0) && (((*myCurrentTextModel)[(std::size_t)-1])->kind() != kind)) { + ((ZLTextPlainModel&)*myCurrentTextModel).createParagraph(kind); + mySectionContainsRegularContents = false; + } + } +} + +void BookReader::insertEndOfSectionParagraph() { + insertEndParagraph(ZLTextParagraph::END_OF_SECTION_PARAGRAPH); +} + +void BookReader::insertEndOfTextParagraph() { + insertEndParagraph(ZLTextParagraph::END_OF_TEXT_PARAGRAPH); +} + +void BookReader::addImageReference(const std::string &id, short vOffset) { + if (myCurrentTextModel != 0) { + mySectionContainsRegularContents = true; + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addImage(id, myModel.imageMap(), vOffset); + } else { + beginParagraph(); + myCurrentTextModel->addControl(IMAGE, true); + myCurrentTextModel->addImage(id, myModel.imageMap(), vOffset); + myCurrentTextModel->addControl(IMAGE, false); + endParagraph(); + } + } +} + +void BookReader::beginContentsParagraph(int referenceNumber) { + if (myCurrentTextModel == myModel.myBookTextModel) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (referenceNumber == -1) { + referenceNumber = myCurrentTextModel->paragraphsNumber(); + } + ZLTextTreeParagraph *peek = myTOCStack.empty() ? 0 : myTOCStack.top(); + if (!myContentsBuffer.empty()) { + contentsModel.addText(myContentsBuffer); + myContentsBuffer.clear(); + myLastTOCParagraphIsEmpty = false; + } + if (myLastTOCParagraphIsEmpty) { + contentsModel.addText("..."); + } + ZLTextTreeParagraph *para = contentsModel.createParagraph(peek); + contentsModel.addControl(CONTENTS_TABLE_ENTRY, true); + contentsModel.setReference(para, referenceNumber); + myTOCStack.push(para); + myLastTOCParagraphIsEmpty = true; + myContentsParagraphExists = true; + } +} + +void BookReader::endContentsParagraph() { + if (!myTOCStack.empty()) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (!myContentsBuffer.empty()) { + contentsModel.addText(myContentsBuffer); + myContentsBuffer.clear(); + myLastTOCParagraphIsEmpty = false; + } + if (myLastTOCParagraphIsEmpty) { + contentsModel.addText("..."); + myLastTOCParagraphIsEmpty = false; + } + myTOCStack.pop(); + } + myContentsParagraphExists = false; +} + +void BookReader::setReference(std::size_t contentsParagraphNumber, int referenceNumber) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (contentsParagraphNumber >= contentsModel.paragraphsNumber()) { + return; + } + contentsModel.setReference((const ZLTextTreeParagraph*)contentsModel[contentsParagraphNumber], referenceNumber); +} + +void BookReader::reset() { + myKindStack.clear(); +} diff --git a/fbreader/src/bookmodel/BookReader.h b/fbreader/src/bookmodel/BookReader.h new file mode 100644 index 0000000..3a27262 --- /dev/null +++ b/fbreader/src/bookmodel/BookReader.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __BOOKREADER_H__ +#define __BOOKREADER_H__ + +#include <vector> +#include <list> +#include <stack> +#include <string> + +#include <ZLTextParagraph.h> + +#include "FBHyperlinkType.h" +#include "FBTextKind.h" + +class BookModel; +class ZLTextModel; +class ZLInputStream; +class ZLTextStyleEntry; + +class BookReader { + +public: + BookReader(BookModel &model); + virtual ~BookReader(); + + void setMainTextModel(); + void setFootnoteTextModel(const std::string &id); + void unsetTextModel(); + + void insertEndOfSectionParagraph(); + void insertEndOfTextParagraph(); + + void pushKind(FBTextKind kind); + bool popKind(); + bool isKindStackEmpty() const; + + void beginParagraph(ZLTextParagraph::Kind kind = ZLTextParagraph::TEXT_PARAGRAPH); + void endParagraph(); + bool paragraphIsOpen() const; + void addControl(FBTextKind kind, bool start); + void addStyleEntry(const ZLTextStyleEntry &entry); + void addStyleCloseEntry(); //TODO reimplement + void addHyperlinkControl(FBTextKind kind, const std::string &label); + void addHyperlinkLabel(const std::string &label); + void addHyperlinkLabel(const std::string &label, int paragraphNumber); + void addFixedHSpace(unsigned char length); + + void addImageReference(const std::string &id, short vOffset = 0); + void addImage(const std::string &id, shared_ptr<const ZLImage> image); + + void beginContentsParagraph(int referenceNumber = -1); + void endContentsParagraph(); + bool contentsParagraphIsOpen() const; + void setReference(std::size_t contentsParagraphNumber, int referenceNumber); + + void addData(const std::string &data); + void addContentsData(const std::string &data); + + void enterTitle() { myInsideTitle = true; } + void exitTitle() { myInsideTitle = false; } + + const BookModel &model() const { return myModel; } + + void reset(); + +private: + void insertEndParagraph(ZLTextParagraph::Kind kind); + void flushTextBufferToParagraph(); + +private: + BookModel &myModel; + shared_ptr<ZLTextModel> myCurrentTextModel; + std::list<shared_ptr<ZLTextModel> > myModelsWithOpenParagraphs; + + std::vector<FBTextKind> myKindStack; + + bool myContentsParagraphExists; + std::stack<ZLTextTreeParagraph*> myTOCStack; + bool myLastTOCParagraphIsEmpty; + + bool mySectionContainsRegularContents; + bool myInsideTitle; + + std::vector<std::string> myBuffer; + std::vector<std::string> myContentsBuffer; + + std::string myHyperlinkReference; + FBHyperlinkType myHyperlinkType; + FBTextKind myHyperlinkKind; +}; + +inline bool BookReader::contentsParagraphIsOpen() const { + return myContentsParagraphExists; +} + +#endif /* __BOOKREADER_H__ */ diff --git a/fbreader/src/bookmodel/FBHyperlinkType.h b/fbreader/src/bookmodel/FBHyperlinkType.h new file mode 100644 index 0000000..fac7d80 --- /dev/null +++ b/fbreader/src/bookmodel/FBHyperlinkType.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __FBHYPERLINKTYPE_H__ +#define __FBHYPERLINKTYPE_H__ + +enum FBHyperlinkType { + HYPERLINK_NONE = 0, + HYPERLINK_INTERNAL = 1, + HYPERLINK_EXTERNAL = 2, + HYPERLINK_BOOK = 3, +}; + +#endif /* __FBHYPERLINKTYPE_H__ */ diff --git a/fbreader/src/bookmodel/FBTextKind.h b/fbreader/src/bookmodel/FBTextKind.h new file mode 100644 index 0000000..746db2b --- /dev/null +++ b/fbreader/src/bookmodel/FBTextKind.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __FBTEXTKIND_H__ +#define __FBTEXTKIND_H__ + +enum FBTextKind { + // please, don't change these numbers + // add new text kinds at end of this enumeration + // + // all the values MUST be in the range 0..127 + REGULAR = 0, + TITLE = 1, + SECTION_TITLE = 2, + POEM_TITLE = 3, + SUBTITLE = 4, + ANNOTATION = 5, + EPIGRAPH = 6, + STANZA = 7, + VERSE = 8, + PREFORMATTED = 9, + IMAGE = 10, + END_OF_SECTION = 11, + CITE = 12, + AUTHOR = 13, + DATEKIND = 14, + INTERNAL_HYPERLINK = 15, + FOOTNOTE = 16, + EMPHASIS = 17, + STRONG = 18, + SUB = 19, + SUP = 20, + CODE = 21, + STRIKETHROUGH = 22, + CONTENTS_TABLE_ENTRY = 23, + //LIBRARY_AUTHOR_ENTRY = 24, + //LIBRARY_BOOK_ENTRY = 25, + LIBRARY_ENTRY = 25, + //RECENT_BOOK_LIST = 26, + ITALIC = 27, + BOLD = 28, + DEFINITION = 29, + DEFINITION_DESCRIPTION = 30, + H1 = 31, + H2 = 32, + H3 = 33, + H4 = 34, + H5 = 35, + H6 = 36, + EXTERNAL_HYPERLINK = 37, + BOOK_HYPERLINK = 38, +}; + +#endif /* __FBTEXTKIND_H__ */ |