bool ZLTextArea::_getHyperlinkInfo(const ZLTextElementRectangle &rectangle, std::string &id, std::string &type, ZLTextKind& hyperlinkKind, int& x1, int&y1, int& x2, int& y2) const { if ((rectangle.Kind != ZLTextElement::WORD_ELEMENT) && (rectangle.Kind != ZLTextElement::IMAGE_ELEMENT)) { return false; } ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(rectangle.ParagraphIndex); cursor.moveToParagraphStart(); hyperlinkKind = REGULAR; for (int i = 0; i < rectangle.ElementIndex; ++i) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); if (control.isHyperlink()) { hyperlinkKind = control.kind(); id = ((const ZLTextHyperlinkControlEntry&)control).label(); type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType(); x1 = rectangle.XStart; y1 = rectangle.YStart; x2 = rectangle.XEnd; y2 = rectangle.YEnd; } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { hyperlinkKind = REGULAR; } } cursor.nextWord(); } return hyperlinkKind != REGULAR; }
ZLTextWordCursor ZLTextAreaController::findStart(const ZLTextWordCursor &end, SizeUnit unit, int size) { ZLTextWordCursor start = end; size -= paragraphHeight(start, true, unit); bool positionChanged = !start.isStartOfParagraph(); start.moveToParagraphStart(); while (size > 0) { if (positionChanged && start.paragraphCursor().isEndOfSection()) { break; } if (!start.previousParagraph()) { break; } if (!start.paragraphCursor().isEndOfSection()) { positionChanged = true; } size -= paragraphHeight(start, false, unit); } skip(start, unit, -size); if (unit != LINE_UNIT) { bool sameStart = start == end; if (!sameStart && start.isEndOfParagraph() && end.isStartOfParagraph()) { ZLTextWordCursor startCopy = start; startCopy.nextParagraph(); sameStart = startCopy == end; } if (sameStart) { start = findStart(end, LINE_UNIT, 1); } } return start; }
bool ScrollToHomeAction::isEnabled() const { if (!isVisible()) { return false; } ZLTextWordCursor cursor = FBReader::Instance().bookTextView().textArea().startCursor(); return cursor.isNull() || !cursor.isStartOfParagraph() || !cursor.paragraphCursor().isFirst(); }
bool BookTextView::getHyperlinkInfo(const ZLTextElementRectangle &rectangle, std::string &id, ZLHyperlinkType &type) const { if ((rectangle.Kind != ZLTextElement::WORD_ELEMENT) && (rectangle.Kind != ZLTextElement::IMAGE_ELEMENT)) { return false; } ZLTextWordCursor cursor = textArea().startCursor(); cursor.moveToParagraph(rectangle.ParagraphIndex); cursor.moveToParagraphStart(); ZLTextKind hyperlinkKind = REGULAR; for (int i = 0; i < rectangle.ElementIndex; ++i) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); if (control.isHyperlink()) { hyperlinkKind = control.kind(); id = ((const ZLTextHyperlinkControlEntry&)control).label(); type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType(); } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { hyperlinkKind = REGULAR; } } cursor.nextWord(); } return hyperlinkKind != REGULAR; }
bool BookTextView::getHyperlinkId(const ZLTextElementArea &area, std::string &id, bool &isExternal) const { if ((area.Kind != ZLTextElement::WORD_ELEMENT) && (area.Kind != ZLTextElement::IMAGE_ELEMENT)) { return false; } ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(area.ParagraphNumber); cursor.moveToParagraphStart(); ZLTextKind hyperlinkKind = REGULAR; for (int i = 0; i < area.TextElementNumber; ++i) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); if (control.isHyperlink()) { hyperlinkKind = control.kind(); id = ((const ZLTextHyperlinkControlEntry&)control).label(); } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { hyperlinkKind = REGULAR; } } cursor.nextWord(); } isExternal = hyperlinkKind == EXTERNAL_HYPERLINK; return hyperlinkKind != REGULAR; }
std::string FBView::word(const ZLTextElementArea &area) const { std::string txt; if (area.Kind == ZLTextElement::WORD_ELEMENT) { ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(area.ParagraphIndex); cursor.moveTo(area.ElementIndex, 0); const ZLTextWord &word = (ZLTextWord&)cursor.element(); ZLUnicodeUtil::Ucs4String ucs4; ZLUnicodeUtil::utf8ToUcs4(ucs4, word.Data, word.Size); ZLUnicodeUtil::Ucs4String::iterator it = ucs4.begin(); while ((it != ucs4.end()) && !ZLUnicodeUtil::isLetter(*it)) { ++it; } if (it != ucs4.end()) { ucs4.erase(ucs4.begin(), it); it = ucs4.end() - 1; while (!ZLUnicodeUtil::isLetter(*it)) { --it; } ucs4.erase(it + 1, ucs4.end()); ZLUnicodeUtil::ucs4ToUtf8(txt, ucs4); } } return txt; }
std::vector<size_t>::const_iterator ZLTextView::nextBreakIterator() const { ZLTextWordCursor cursor = endCursor(); if (cursor.isNull()) { cursor = startCursor(); } if (cursor.isNull()) { return myTextBreaks.begin(); } return std::lower_bound(myTextBreaks.begin(), myTextBreaks.end(), cursor.paragraphCursor().index()); }
void ZLTextView::ViewStyle::applyControls(const ZLTextWordCursor &begin, const ZLTextWordCursor &end) { for (ZLTextWordCursor cursor = begin; !cursor.equalWordNumber(end); cursor.nextWord()) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { applyControl((ZLTextControlElement&)element); } else if (element.kind() == ZLTextElement::FORCED_CONTROL_ELEMENT) { applyControl((ZLTextForcedControlElement&)element); } } }
bool strongContains(const ZLTextSelectionModel::Range &range, const ZLTextWordCursor &cursor) { const int pn = cursor.paragraphCursor().index(); const int wn = cursor.elementIndex(); return ((range.first.ParagraphIndex < pn) || ((range.first.ParagraphIndex == pn) && (range.first.ElementIndex < wn))) && ((range.second.ParagraphIndex > pn) || ((range.second.ParagraphIndex == pn) && (range.second.ElementIndex > wn))); }
size_t ZLTextView::PositionIndicator::sizeOfTextBeforeCursor(const ZLTextWordCursor &cursor) const { const size_t paragraphIndex = cursor.paragraphCursor().index(); const size_t paragraphLength = cursor.paragraphCursor().paragraphLength(); if (paragraphLength == 0) { return sizeOfTextBeforeParagraph(paragraphIndex); } else { return sizeOfTextBeforeParagraph(paragraphIndex) + muldiv(sizeOfParagraph(paragraphIndex), cursor.elementIndex(), paragraphLength); } }
void IfEmptyWordList() { if (acwlistcount == 0) { ZLTextWordCursor cr = is_footnote_mode() ? footview->textArea().startCursor() : bookview->textArea().startCursor(); int paragraph = !cr.isNull() ? cr.paragraphCursor().index() : 0; if (acwlistcount + 3 >= acwlistsize) { acwlistsize = acwlistsize + (acwlistsize >> 1) + 64; acwordlist = (SynWordList *)realloc(acwordlist, acwlistsize * sizeof(SynWordList)); }
ZLTextWordCursor ZLTextAreaController::buildInfos(const ZLTextWordCursor &start) { myArea.myLineInfos.clear(); ZLTextWordCursor cursor = start; int textHeight = myArea.height(); int counter = 0; do { ZLTextWordCursor paragraphEnd = cursor; paragraphEnd.moveToParagraphEnd(); ZLTextWordCursor paragraphStart = cursor; paragraphStart.moveToParagraphStart(); ZLTextArea::Style style(myArea, myArea.myProperties.baseStyle()); style.applyControls(paragraphStart, cursor); ZLTextLineInfoPtr info = new ZLTextLineInfo(cursor, style.textStyle(), style.bidiLevel()); while (!info->End.isEndOfParagraph()) { info = myArea.processTextLine(style, info->End, paragraphEnd); textHeight -= info->Height + info->Descent; if ((textHeight < 0) && (counter > 0)) { break; } textHeight -= info->VSpaceAfter; cursor = info->End; myArea.myLineInfos.push_back(info); if (textHeight < 0) { break; } ++counter; } } while (cursor.isEndOfParagraph() && cursor.nextParagraph() && !cursor.paragraphCursor().isEndOfSection() && (textHeight >= 0)); return cursor; }
void ZLTextAreaController::skip(ZLTextWordCursor &cursor, SizeUnit unit, int size) { ZLTextWordCursor paragraphStart = cursor; paragraphStart.moveToParagraphStart(); ZLTextWordCursor paragraphEnd = cursor; paragraphEnd.moveToParagraphEnd(); ZLTextArea::Style style(myArea, myArea.myProperties.baseStyle()); style.applyControls(paragraphStart, cursor); while (!cursor.isEndOfParagraph() && (size > 0)) { const ZLTextLineInfoPtr info = myArea.processTextLine(style, cursor, paragraphEnd); cursor = info->End; size -= infoHeight(*info, unit); } }
bool CollectionView::_onStylusPress(int x, int y) { fbreader().setHyperlinkCursor(false); const ZLTextElementArea *imageArea = elementByCoordinates(x, y); if ((imageArea != 0) && (imageArea->Kind == ZLTextElement::IMAGE_ELEMENT)) { ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(imageArea->ParagraphIndex); cursor.moveTo(imageArea->ElementIndex, 0); const ZLTextElement &element = cursor.element(); if (element.kind() != ZLTextElement::IMAGE_ELEMENT) { return false; } const ZLTextImageElement &imageElement = (ZLTextImageElement&)element; const std::string &id = imageElement.id(); if (id == CollectionModel::BookInfoImageId) { editBookInfo(collectionModel().bookByParagraphIndex(imageArea->ParagraphIndex)); return true; } else if (id == CollectionModel::RemoveBookImageId) { removeBook(collectionModel().bookByParagraphIndex(imageArea->ParagraphIndex)); return true; } else if (id == CollectionModel::RemoveTagImageId) { removeTag(collectionModel().tagByParagraphIndex(imageArea->ParagraphIndex)); return true; } else if (id == CollectionModel::TagInfoImageId) { editTagInfo(collectionModel().tagByParagraphIndex(imageArea->ParagraphIndex)); return true; } else { return false; } } int index = paragraphIndexByCoordinates(x, y); if (index == -1) { return false; } BookDescriptionPtr book = collectionModel().bookByParagraphIndex(index); if (!book.isNull()) { fbreader().openBook(book); fbreader().showBookTextView(); return true; } return false; }
void ZLTextView::PositionIndicator::draw() { ZLTextBaseStyle &baseStyle = ZLTextStyleCollection::instance().baseStyle(); ZLPaintContext &context = this->context(); ZLTextWordCursor endCursor = myTextView.endCursor(); bool isEndOfText = false; if (endCursor.isEndOfParagraph()) { isEndOfText = !endCursor.nextParagraph(); } myExtraWidth = 0; if (myInfo.isTimeShown()) { drawExtraText(timeString()); } if (myInfo.isBatteryShown()) { drawExtraText(batteryString()); } if (myInfo.isTextPositionShown()) { drawExtraText(textPositionString()); } const long bottom = this->bottom(); const long top = this->top(); const long left = this->left(); const long right = this->right(); if (left >= right) { return; } size_t fillWidth = right - left - 1; if (!isEndOfText) { fillWidth = muldiv(fillWidth, sizeOfTextBeforeCursor(myTextView.endCursor()), sizeOfTextBeforeParagraph(endTextIndex())); } context.setColor(baseStyle.RegularTextColorOption.value()); context.setFillColor(myInfo.color()); context.fillRectangle(myTextView.visualX(left + 1), top + 1, myTextView.visualX(left + fillWidth + 1), bottom - 1); context.drawLine(myTextView.visualX(left), top, myTextView.visualX(right), top); context.drawLine(myTextView.visualX(left), bottom, myTextView.visualX(right), bottom); context.drawLine(myTextView.visualX(left), bottom, myTextView.visualX(left), top); context.drawLine(myTextView.visualX(right), bottom, myTextView.visualX(right), top); }
int ZLTextAreaController::paragraphHeight(const ZLTextWordCursor &cursor, bool beforeCurrentPosition, SizeUnit unit) { ZLTextWordCursor word = cursor; word.moveToParagraphStart(); ZLTextWordCursor end = cursor; if (!beforeCurrentPosition) { end.moveToParagraphEnd(); } int size = 0; ZLTextArea::Style style(myArea, myArea.myProperties.baseStyle()); while (!word.equalElementIndex(end)) { const ZLTextLineInfoPtr info = myArea.processTextLine(style, word, end); word = info->End; size += infoHeight(*info, unit); } return size; }
size_t ZLTextView::PositionIndicator::sizeOfTextBeforeParagraph(size_t paragraphIndex) const { if (myTextView.myModel->kind() == ZLTextModel::TREE_MODEL) { ZLTextWordCursor cursor = myTextView.startCursor(); if (cursor.isNull()) { cursor = myTextView.endCursor(); } if (!cursor.isNull()) { const ZLTextTreeModel &treeModel = (const ZLTextTreeModel&)*myTextView.myModel; size_t sum = 0; for (size_t i = 0; i < paragraphIndex; ++i) { const ZLTextTreeParagraph *para = (const ZLTextTreeParagraph*)treeModel[i]; if (para->parent()->isOpen()) { sum += sizeOfParagraph(i); } } return sum; } } return myTextView.myTextSize[paragraphIndex] - myTextView.myTextSize[startTextIndex()]; }
void ZLTextSelectionModel::extendWordSelectionToParagraph() { clear(); myFirstBound.Before.ElementIndex = 0; myFirstBound.Before.CharIndex = 0; myFirstBound.After = myFirstBound.Before; ZLTextWordCursor cursor = myView.startCursor(); cursor.moveToParagraph(myFirstBound.Before.ParagraphIndex); cursor.moveToParagraphEnd(); mySecondBound.Before.ElementIndex = cursor.elementIndex(); mySecondBound.Before.CharIndex = 0; mySecondBound.After = mySecondBound.Before; myIsEmpty = false; myTextIsUpToDate = false; myRangeVectorIsUpToDate = false; myDoUpdate = false; }
void ZLTextView::PositionIndicator::draw() { ZLPaintContext &context = this->context(); ZLTextWordCursor endCursor = myTextView.textArea().endCursor(); bool isEndOfText = false; if (endCursor.isEndOfParagraph()) { isEndOfText = !endCursor.nextParagraph(); } myExtraWidth = 0; if (myInfo.isTimeShown()) { drawExtraText(timeString()); } if (myInfo.isTextPositionShown()) { drawExtraText(textPositionString()); } const long bottom = this->bottom(); const long top = this->top(); const long left = this->left(); const long right = this->right(); if (left >= right) { return; } size_t fillWidth = right - left - 1; if (!isEndOfText) { fillWidth = muldiv(fillWidth, sizeOfTextBeforeCursor(myTextView.textArea().endCursor()), sizeOfTextBeforeParagraph(endTextIndex())); } context.setColor(myTextView.color()); context.setFillColor(myInfo.color()); context.fillRectangle(left + 1, top + 1, left + fillWidth + 1, bottom - 1); context.drawLine(left, top, right, top); context.drawLine(left, bottom, right, bottom); context.drawLine(left, bottom, left, top); context.drawLine(right, bottom, right, top); }
void ZLTextSelectionModel::extendWordSelectionToParagraph() { clear(); myFirstBound.Before.ElementIndex = 0; myFirstBound.Before.CharIndex = 0; myFirstBound.After = myFirstBound.Before; ZLTextWordCursor cursor = myArea.startCursor(); cursor.moveToParagraph(myFirstBound.Before.ParagraphIndex); cursor.moveToParagraphEnd(); mySecondBound.Before.ElementIndex = cursor.elementIndex(); mySecondBound.Before.CharIndex = 0; mySecondBound.After = mySecondBound.Before; myIsEmpty = false; myTextIsUpToDate = false; myRangeVectorIsUpToDate = false; copySelectionToClipboard(ZLDialogManager::CLIPBOARD_SELECTION); }
int ZLTextSelectionModel::charIndex(const ZLTextElementArea &area, int x) { myView.myStyle.setTextStyle(area.Style, area.BidiLevel); ZLTextWordCursor cursor = myView.startCursor(); cursor.moveToParagraph(area.ParagraphIndex); const ZLTextWord &word = (const ZLTextWord&)cursor.paragraphCursor()[area.ElementIndex]; const bool mainDir = area.BidiLevel % 2 == myView.myStyle.baseBidiLevel() % 2; const int deltaX = mainDir ? x - area.XStart : area.XEnd - x; const int len = area.Length; const int start = area.StartCharIndex; int diff = deltaX; int previousDiff = diff; int index; for (index = 0; (index < len) && (diff > 0); ++index) { previousDiff = diff; diff = deltaX - myView.myStyle.wordWidth(word, start, index + 1); } if (previousDiff + diff < 0) { --index; } return start + index; }
int ZLTextSelectionModel::charIndex(const ZLTextElementRectangle &rectangle, int x) { int x1 = x - myArea.hOffset(); ZLTextArea::Style style(myArea, rectangle.Style); style.setTextStyle(rectangle.Style, rectangle.BidiLevel); ZLTextWordCursor cursor = myArea.startCursor(); cursor.moveToParagraph(rectangle.ParagraphIndex); const ZLTextWord &word = (const ZLTextWord&)cursor.paragraphCursor()[rectangle.ElementIndex]; const bool mainDir = rectangle.BidiLevel % 2 == (myArea.isRtl() ? 1 : 0); const int deltaX = mainDir ? x1 - rectangle.XStart : rectangle.XEnd - x1; const int len = rectangle.Length; const int start = rectangle.StartCharIndex; int diff = deltaX; int previousDiff = diff; int index; for (index = 0; (index < len) && (diff > 0); ++index) { previousDiff = diff; diff = deltaX - style.wordWidth(word, start, index + 1); } if (previousDiff + diff < 0) { --index; } return start + index; }
std::string BookTextView::getFirstInternalHyperlinkId(int x0, int y0, int x1, int y1) { std::string id; std::string type; const ZLTextElementArea * area = elementByCoordinates(x0, y0); const ZLTextElementArea * stop_area = elementByCoordinates(x1, y1); if ( !area || ((area->Kind != ZLTextElement::WORD_ELEMENT) && (area->Kind != ZLTextElement::IMAGE_ELEMENT))) { return id; } ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(area->ParagraphIndex); int paragraphs = area->ParagraphIndex; int end_paragraphs = stop_area ? stop_area->ParagraphIndex : 0; do { cursor.moveToParagraphStart(); ZLTextKind hyperlinkKind = REGULAR; for ( ; !cursor.isEndOfParagraph();) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); if (control.isHyperlink()) { hyperlinkKind = control.kind(); id = ((const ZLTextHyperlinkControlEntry&)control).label(); type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType(); if (type == "internal") { return id; } } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { hyperlinkKind = REGULAR; } } cursor.nextWord(); } } while( ++paragraphs <= end_paragraphs && cursor.nextParagraph()); return std::string(); }
BookTextView::Position BookTextView::cursorPosition(const ZLTextWordCursor &cursor) const { return Position(cursor.paragraphCursor().index(), cursor.elementIndex(), cursor.charIndex()); }
BookTextView::Position BookTextView::cursorPosition(const ZLTextWordCursor &cursor) const { return Position(cursor.paragraphCursor().index(), cursor.wordNumber()); }
bool ZLTextSelectionModel::selectWord(int x, int y) { clear(); const ZLTextElementRectangle *rectangle = myArea.elementByCoordinates(x, y); if (rectangle == 0) { return false; } int startIndex = 0; int endIndex = 1; switch (rectangle->Kind) { default: return false; case ZLTextElement::IMAGE_ELEMENT: break; case ZLTextElement::WORD_ELEMENT: { ZLTextWordCursor cursor = myArea.startCursor(); cursor.moveToParagraph(rectangle->ParagraphIndex); const ZLTextWord &word = (const ZLTextWord&)cursor.paragraphCursor()[rectangle->ElementIndex]; ZLUnicodeUtil::Ucs4String ucs4string; ZLUnicodeUtil::utf8ToUcs4(ucs4string, word.Data, word.Size); startIndex = charIndex(*rectangle, x); if (startIndex == word.Length) { --startIndex; } endIndex = startIndex + 1; ZLUnicodeUtil::Ucs4Char ch = ucs4string[startIndex]; if (ZLUnicodeUtil::isLetter(ch) || (('0' <= ch) && (ch <= '9'))) { while (--startIndex >= 0) { ch = ucs4string[startIndex]; if (!ZLUnicodeUtil::isLetter(ch) && ((ch < '0') || (ch > '9'))) { break; } } ++startIndex; while (++endIndex <= word.Length) { ch = ucs4string[endIndex - 1]; if (!ZLUnicodeUtil::isLetter(ch) && ((ch < '0') || (ch > '9'))) { break; } } --endIndex; } } } myFirstBound.Before.Exists = true; myFirstBound.Before.ParagraphIndex = rectangle->ParagraphIndex; myFirstBound.Before.ElementIndex = rectangle->ElementIndex; myFirstBound.Before.CharIndex = startIndex; myFirstBound.After = myFirstBound.Before; mySecondBound.Before = myFirstBound.Before; mySecondBound.Before.CharIndex = endIndex; mySecondBound.After = mySecondBound.Before; myIsEmpty = false; myTextIsUpToDate = false; myRangeVectorIsUpToDate = false; copySelectionToClipboard(ZLDialogManager::CLIPBOARD_SELECTION); return true; }
bool NetLibraryView::_onStylusPress(int x, int y) { fbreader().setHyperlinkCursor(false); if (model().isNull()) { return false; } const ZLTextElementArea *imageArea = elementByCoordinates(x, y); if ((imageArea == 0) || (imageArea->Kind != ZLTextElement::IMAGE_ELEMENT)) { return false; } ZLTextWordCursor cursor = startCursor(); cursor.moveToParagraph(imageArea->ParagraphIndex); cursor.moveTo(imageArea->ElementIndex, 0); const ZLTextElement &element = cursor.element(); if (element.kind() != ZLTextElement::IMAGE_ELEMENT) { return false; } const ZLTextImageElement &imageElement = (ZLTextImageElement&)element; const std::string &id = imageElement.id(); shared_ptr<NetworkBookInfo> book = myParagraphToBookMap[imageArea->ParagraphIndex]; if (book.isNull()) { return false; } if ((id == DownloadEpub) || (id == DownloadMobi)) { if (!ZLNetworkManager::instance().connect()) { NetworkOperationRunnable::showErrorMessage( ZLResource::resource("dialog") ["networkError"] ["couldntConnectToNetworkMessage"].value() ); return false; } NetworkBookInfo::URLType format = (id == DownloadEpub) ? NetworkBookInfo::BOOK_EPUB : NetworkBookInfo::BOOK_MOBIPOCKET; DownloadBookRunnable downloader(*book, format); downloader.executeWithUI(); if (downloader.hasErrors()) { downloader.showErrorMessage(); } else { BookDescriptionPtr description = BookDescription::getDescription(downloader.fileName()); WritableBookDescription wDescription(*description); wDescription.clearAuthor(); wDescription.addAuthor(book->Author.DisplayName, book->Author.SortKey); wDescription.title() = book->Title; wDescription.language() = book->Language; for (std::vector<std::string>::const_iterator it = book->Tags.begin(); it != book->Tags.end(); ++it) { wDescription.addTag(*it); } wDescription.saveInfo(); fbreader().openBook(description); fbreader().setMode(FBReader::BOOK_TEXT_MODE); rebuildModel(); } return true; } else if ((id == ReadLocalEpub) || (id == ReadLocalMobi)) { NetworkBookInfo::URLType format = (id == DownloadEpub) ? NetworkBookInfo::BOOK_EPUB : NetworkBookInfo::BOOK_MOBIPOCKET; fbreader().openFile(NetworkLinkCollection::instance().bookFileName(book->URLByType[format])); fbreader().setMode(FBReader::BOOK_TEXT_MODE); return true; } else if (id == OpenInBrowser) { std::string url = book->URLByType[NetworkBookInfo::LINK_HTTP]; shared_ptr<ProgramCollection> collection = fbreader().webBrowserCollection(); if (!url.empty() && !collection.isNull()) { shared_ptr<Program> program = collection->currentProgram(); if (!program.isNull()) { program->run("openLink", url); } } return true; } return false; }
void ZLTextSelectionModel::createData() const { if (!myTextIsUpToDate && !isEmpty()) { Range r = internalRange(); ZLTextWordCursor start = myArea.startCursor(); start.moveToParagraph(r.first.ParagraphIndex); start.moveTo(r.first.ElementIndex, r.first.CharIndex); ZLTextWordCursor end = myArea.startCursor(); end.moveToParagraph(r.second.ParagraphIndex); end.moveTo(r.second.ElementIndex, r.second.CharIndex); std::set<ZLTextParagraphCursorPtr> pcursors; pcursors.insert(start.paragraphCursorPtr()); ZLTextWordCursor cursor = start; while (cursor < end) { if (cursor.isEndOfParagraph()) { cursor.nextParagraph(); pcursors.insert(cursor.paragraphCursorPtr()); myText.append(ZLibrary::EndOfLine); continue; } const ZLTextElement &element = cursor.element(); switch (element.kind()) { case ZLTextElement::WORD_ELEMENT: { const ZLTextWord &word = (const ZLTextWord&)element; if (cursor.sameElementAs(end)) { if (start.sameElementAs(end)) { int skip = ZLUnicodeUtil::length(word.Data, start.charIndex()); int length = ZLUnicodeUtil::length(word.Data, end.charIndex()) - skip; myText.append(word.Data + skip, length); } else { myText.append(word.Data, ZLUnicodeUtil::length(word.Data, end.charIndex())); } } else if (cursor.charIndex() == 0) { myText.append(word.Data, word.Size); } else /* cursor == start */ { int skip = ZLUnicodeUtil::length(word.Data, cursor.charIndex()); myText.append(word.Data + skip, word.Size - skip); } break; } case ZLTextElement::IMAGE_ELEMENT: if (myImage.isNull()) { myImage = ((const ZLTextImageElement&)element).image(); } break; case ZLTextElement::HSPACE_ELEMENT: case ZLTextElement::NB_HSPACE_ELEMENT: myText += ' '; break; default: break; } cursor.nextWord(); } if ((cursor == end) && !cursor.isEndOfParagraph() && myImage.isNull()) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::IMAGE_ELEMENT) { myImage = ((const ZLTextImageElement&)element).image(); } } myCursors.swap(pcursors); myTextIsUpToDate = true; } }
bool ZLTextAreaController::preparePaintInfo() { if ((myPaintState == NOTHING_TO_PAINT) || (myPaintState == READY)) { return false; } myArea.myLineInfoCache.insert(myArea.myLineInfos.begin(), myArea.myLineInfos.end()); switch (myPaintState) { default: break; case TO_SCROLL_FORWARD: if (!myArea.myEndCursor.paragraphCursor().isLast() || !myArea.myEndCursor.isEndOfParagraph()) { ZLTextWordCursor startCursor; switch (myScrollingMode) { case NO_OVERLAPPING: break; case KEEP_LINES: startCursor = findLineFromEnd(myOverlappingValue); break; case SCROLL_LINES: startCursor = findLineFromStart(myOverlappingValue); if (startCursor.isEndOfParagraph()) { startCursor.nextParagraph(); } break; case SCROLL_PERCENTAGE: startCursor = findPercentFromStart(myOverlappingValue); break; } if (!startCursor.isNull() && (startCursor == myArea.myStartCursor)) { startCursor = findLineFromStart(1); } if (!startCursor.isNull()) { ZLTextWordCursor endCursor = buildInfos(startCursor); if (!visiblePageIsEmpty() && ((myScrollingMode != KEEP_LINES) || (endCursor != myArea.myEndCursor))) { myArea.myStartCursor = startCursor; myArea.myEndCursor = endCursor; break; } } myArea.myStartCursor = myArea.myEndCursor; myArea.myEndCursor = buildInfos(myArea.myStartCursor); } break; case TO_SCROLL_BACKWARD: if (!myArea.myStartCursor.paragraphCursor().isFirst() || !myArea.myStartCursor.isStartOfParagraph()) { switch (myScrollingMode) { case NO_OVERLAPPING: myArea.myStartCursor = findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height()); break; case KEEP_LINES: { ZLTextWordCursor endCursor = findLineFromStart(myOverlappingValue); if (!endCursor.isNull() && (endCursor == myArea.myEndCursor)) { endCursor = findLineFromEnd(1); } if (!endCursor.isNull()) { ZLTextWordCursor startCursor = findStart(endCursor, PIXEL_UNIT, myArea.height()); myArea.myStartCursor = (startCursor != myArea.myStartCursor) ? startCursor : findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height()); } else { myArea.myStartCursor = findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height()); } break; } case SCROLL_LINES: myArea.myStartCursor = findStart(myArea.myStartCursor, LINE_UNIT, myOverlappingValue); break; case SCROLL_PERCENTAGE: myArea.myStartCursor = findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height() * myOverlappingValue / 100); break; } myArea.myEndCursor = buildInfos(myArea.myStartCursor); if (visiblePageIsEmpty()) { myArea.myStartCursor = findStart(myArea.myStartCursor, LINE_UNIT, 1); myArea.myEndCursor = buildInfos(myArea.myStartCursor); } } break; case START_IS_KNOWN: myArea.myEndCursor = buildInfos(myArea.myStartCursor); if (visiblePageIsEmpty()) { ZLTextWordCursor startCursor = findLineFromStart(1); if (!startCursor.isNull()) { myArea.myStartCursor = startCursor; if (myArea.myStartCursor.isEndOfParagraph()) { myArea.myStartCursor.nextParagraph(); } myArea.myEndCursor = buildInfos(myArea.myStartCursor); } } break; case END_IS_KNOWN: myArea.myStartCursor = findStart(myArea.myEndCursor, PIXEL_UNIT, myArea.height()); myArea.myEndCursor = buildInfos(myArea.myStartCursor); break; } myPaintState = READY; myArea.myLineInfoCache.clear(); return true; }
void ZLTextView::prepareTextLine(const ZLTextLineInfo &info, int y) { y = std::min(y + info.Height, topMargin() + textAreaHeight()); myStyle.setTextStyle(info.StartStyle, info.StartBidiLevel); int spaceCounter = info.SpaceCounter; int fullCorrection = 0; const bool endOfParagraph = info.End.isEndOfParagraph(); bool wordOccured = false; int x = lineStartMargin() + info.StartIndent; const int fontSize = myStyle.textStyle()->fontSize(); // TODO: change metrics at font change const ZLTextStyleEntry::Metrics metrics(fontSize, fontSize / 2, viewWidth(), textAreaHeight()); switch (myStyle.textStyle()->alignment()) { case ALIGN_RIGHT: if (!myStyle.baseIsRtl()) { x += metrics.FullWidth - myStyle.textStyle()->lineEndIndent(metrics, myStyle.baseIsRtl()) - info.Width; } break; case ALIGN_LEFT: if (myStyle.baseIsRtl()) { x += metrics.FullWidth - myStyle.textStyle()->lineEndIndent(metrics, myStyle.baseIsRtl()) - info.Width; } break; case ALIGN_LINESTART: break; case ALIGN_CENTER: x += (metrics.FullWidth - myStyle.textStyle()->lineEndIndent(metrics, myStyle.baseIsRtl()) - info.Width) / 2; break; case ALIGN_JUSTIFY: if (!endOfParagraph && (info.End.element().kind() != ZLTextElement::AFTER_PARAGRAPH_ELEMENT)) { fullCorrection = metrics.FullWidth - myStyle.textStyle()->lineEndIndent(metrics, myStyle.baseIsRtl()) - info.Width; } break; case ALIGN_UNDEFINED: break; } const ZLTextParagraphCursor ¶graph = info.RealStart.paragraphCursor(); int paragraphIndex = paragraph.index(); for (ZLTextWordCursor pos = info.RealStart; !pos.equalElementIndex(info.End); pos.nextWord()) { const ZLTextElement &element = paragraph[pos.elementIndex()]; ZLTextElement::Kind kind = element.kind(); int width = myStyle.elementWidth(element, pos.charIndex(), metrics); myStyle.applySingleControl(element); switch (kind) { case ZLTextElement::WORD_ELEMENT: case ZLTextElement::IMAGE_ELEMENT: { const int height = myStyle.elementHeight(element, metrics); const int descent = myStyle.elementDescent(element); const int length = (kind == ZLTextElement::WORD_ELEMENT) ? ((const ZLTextWord&)element).Length - pos.charIndex() : 0; addAreaToTextMap( ZLTextElementArea( paragraphIndex, pos.elementIndex(), pos.charIndex(), length, false, myStyle.textStyle(), kind, x, x + width - 1, y - height + 1, y + descent, myStyle.bidiLevel() ) ); wordOccured = true; break; } case ZLTextElement::CONTROL_ELEMENT: case ZLTextElement::FORCED_CONTROL_ELEMENT: break; case ZLTextElement::HSPACE_ELEMENT: case ZLTextElement::NB_HSPACE_ELEMENT: if (wordOccured && (spaceCounter > 0)) { int correction = fullCorrection / spaceCounter; x += context().spaceWidth() + correction; fullCorrection -= correction; wordOccured = false; --spaceCounter; } break; case ZLTextElement::INDENT_ELEMENT: case ZLTextElement::BEFORE_PARAGRAPH_ELEMENT: case ZLTextElement::AFTER_PARAGRAPH_ELEMENT: case ZLTextElement::EMPTY_LINE_ELEMENT: case ZLTextElement::FIXED_HSPACE_ELEMENT: break; case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT: //context().setColor(ZLColor(0, 255, 0)); //context().drawLine(visualX(x), y, visualX(x), y - 20); break; case ZLTextElement::END_REVERSED_SEQUENCE_ELEMENT: flushRevertedElements(myStyle.bidiLevel()); //context().setColor(ZLColor(255, 0, 0)); //context().drawLine(visualX(x), y, visualX(x), y - 20); break; } x += width; } if (!endOfParagraph && (info.End.element().kind() == ZLTextElement::WORD_ELEMENT)) { int start = 0; if (info.End.equalElementIndex(info.RealStart)) { start = info.RealStart.charIndex(); } const int len = info.End.charIndex() - start; if (len > 0) { const ZLTextWord &word = (const ZLTextWord&)info.End.element(); ZLUnicodeUtil::Ucs4String ucs4string; ZLUnicodeUtil::utf8ToUcs4(ucs4string, word.Data, word.Size); const bool addHyphenationSign = ucs4string[start + len - 1] != '-'; const int width = myStyle.wordWidth(word, start, len, addHyphenationSign); const int height = myStyle.elementHeight(word, metrics); const int descent = myStyle.elementDescent(word); addAreaToTextMap( ZLTextElementArea( paragraphIndex, info.End.elementIndex(), start, len, addHyphenationSign, myStyle.textStyle(), ZLTextElement::WORD_ELEMENT, x, x + width - 1, y - height + 1, y + descent, word.BidiLevel ) ); } } for (unsigned char i = myStyle.bidiLevel(); i > myStyle.baseBidiLevel(); --i) { flushRevertedElements(i - 1); } }