/* * Copyright (C) 2004-2012 Geometer Plus * * 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 #include #include #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 >::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 >::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::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 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(); }