From a118655e90bae1f8668fb1a8b08ca9d3399e4804 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Tue, 12 May 2009 22:46:36 +0000 Subject: [PATCH] hyperlink navigation (in progress) TOC for mobipocket files (in progress) git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@974 6a642e6f-84f6-412e-ac94-c4a38d5a04b0 --- .../android/fbreader/BookmarksActivity.java | 5 ++- .../android/fbreader/TOCActivity.java | 2 +- .../fbreader/fbreader/BookTextView.java | 10 ----- .../fbreader/fbreader/FBReader.java | 2 +- .../fbreader/fbreader/FBView.java | 22 +++++++++++ .../fbreader/TrackballScrollingAction.java | 4 +- .../fbreader/formats/html/HtmlReader.java | 7 +++- .../fbreader/formats/html/HtmlTag.java | 13 ++++++- .../formats/pdb/MobipocketHtmlBookReader.java | 37 ++++++++++++++++++ .../zlibrary/core/html/ZLHtmlParser.java | 20 ++++++---- .../zlibrary/core/html/ZLHtmlReader.java | 2 +- .../text/view/ZLTextElementAreaVector.java | 39 ++----------------- .../zlibrary/text/view/ZLTextView.java | 10 ++++- 13 files changed, 108 insertions(+), 65 deletions(-) diff --git a/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java b/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java index d15787a5d..08855e2f1 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java +++ b/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java @@ -245,13 +245,16 @@ mainLoop: case '.': case '!': case '?': + ++sentenceCounter; + case ',': + case ':': + case ';': if (appendLineBreak) { builder.append("\n"); appendLineBreak = false; } builder.append(sentenceBuilder); sentenceBuilder.delete(0, sentenceBuilder.length()); - ++sentenceCounter; storedWordCounter = wordCounter; } } diff --git a/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java b/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java index d58abb2a8..6ff0a3120 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java +++ b/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java @@ -124,7 +124,7 @@ public class TOCActivity extends ListActivity { final TOCTree.Reference reference = tree.getReference(); if (reference != null) { final FBReader fbreader = (FBReader)ZLApplication.Instance(); - fbreader.BookTextView.gotoParagraphSafe(reference.ParagraphIndex); + fbreader.BookTextView.gotoParagraph(reference.ParagraphIndex, false); finish(); } } diff --git a/src/org/geometerplus/fbreader/fbreader/BookTextView.java b/src/org/geometerplus/fbreader/fbreader/BookTextView.java index d658e96bd..cde320a79 100644 --- a/src/org/geometerplus/fbreader/fbreader/BookTextView.java +++ b/src/org/geometerplus/fbreader/fbreader/BookTextView.java @@ -47,16 +47,6 @@ public class BookTextView extends FBView { preparePaintInfo(); ZLApplication.Instance().repaintView(); } - - public void gotoParagraphSafe(int paragraphIndex) { - preparePaintInfo(); - final ZLTextWordCursor cursor = getStartCursor(); - if (!cursor.isNull()) { - final ZLTextPosition position = new ZLTextPosition(cursor); - gotoParagraph(paragraphIndex, false); - preparePaintInfo(); - } - } public boolean onStylusPress(int x, int y) { ZLTextElementArea area = getElementByCoordinates(x, y); diff --git a/src/org/geometerplus/fbreader/fbreader/FBReader.java b/src/org/geometerplus/fbreader/fbreader/FBReader.java index 8a7ffb38b..d3b913bea 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReader.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReader.java @@ -190,7 +190,7 @@ public final class FBReader extends ZLApplication { BookModel.Label label = Model.getLabel(id); if ((label != null) && (label.Model != null)) { if (label.Model == Model.BookTextModel) { - BookTextView.gotoParagraphSafe(label.ParagraphIndex); + BookTextView.gotoParagraph(label.ParagraphIndex, false); } else { FootnoteView.setModel(label.Model); setMode(ViewMode.FOOTNOTE); diff --git a/src/org/geometerplus/fbreader/fbreader/FBView.java b/src/org/geometerplus/fbreader/fbreader/FBView.java index e0ed02dec..014ffc70b 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBView.java +++ b/src/org/geometerplus/fbreader/fbreader/FBView.java @@ -42,7 +42,29 @@ public abstract class FBView extends ZLTextView { super(context); } + private int myHyperlinkIndex = -1; + private int myHyperlinkCount = -1; + + final void doShortScroll(boolean forward) { + System.err.println("count = " + myHyperlinkCount); + if (myHyperlinkCount == -1) { + myHyperlinkCount = 0; + for (ZLTextElementArea area : allElements()) { + } + } + scrollPage(forward, ZLTextView.ScrollingMode.SCROLL_LINES, 1); + ZLApplication.Instance().repaintView(); + } + + public void onScrollingFinished(int viewPage) { + if (viewPage != PAGE_CENTRAL) { + myHyperlinkCount = -1; + } + super.onScrollingFinished(viewPage); + } + final void doScrollPage(boolean forward) { + myHyperlinkCount = -1; final ScrollingPreferences preferences = ScrollingPreferences.Instance(); if (preferences.AnimateOption.getValue()) { if (forward) { diff --git a/src/org/geometerplus/fbreader/fbreader/TrackballScrollingAction.java b/src/org/geometerplus/fbreader/fbreader/TrackballScrollingAction.java index 98875db21..e8bc17829 100644 --- a/src/org/geometerplus/fbreader/fbreader/TrackballScrollingAction.java +++ b/src/org/geometerplus/fbreader/fbreader/TrackballScrollingAction.java @@ -30,12 +30,10 @@ class TrackballScrollingAction extends FBAction { } public boolean isEnabled() { - // TODO: implement return true; } public void run() { - Reader.getTextView().scrollPage(myForward, ZLTextView.ScrollingMode.SCROLL_LINES, 1); - Reader.repaintView(); + Reader.getTextView().doShortScroll(myForward); } } diff --git a/src/org/geometerplus/fbreader/formats/html/HtmlReader.java b/src/org/geometerplus/fbreader/formats/html/HtmlReader.java index 918573fdc..7ceb44260 100644 --- a/src/org/geometerplus/fbreader/formats/html/HtmlReader.java +++ b/src/org/geometerplus/fbreader/formats/html/HtmlReader.java @@ -228,8 +228,11 @@ public class HtmlReader extends BookReader implements ZLHtmlReader { } } - public void startElementHandler(String tagName, ZLHtmlAttributeMap attributes) { - final byte tag = HtmlTag.getTagByName(tagName); + public void startElementHandler(String tagName, int offset, ZLHtmlAttributeMap attributes) { + startElementHandler(HtmlTag.getTagByName(tagName), offset, attributes); + } + + public void startElementHandler(byte tag, int offset, ZLHtmlAttributeMap attributes) { switch (tag) { case HtmlTag.HTML: break; diff --git a/src/org/geometerplus/fbreader/formats/html/HtmlTag.java b/src/org/geometerplus/fbreader/formats/html/HtmlTag.java index d7459babf..29aed24c9 100644 --- a/src/org/geometerplus/fbreader/formats/html/HtmlTag.java +++ b/src/org/geometerplus/fbreader/formats/html/HtmlTag.java @@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.html; import java.util.*; import org.geometerplus.zlibrary.core.util.*; -final class HtmlTag { +public final class HtmlTag { public static final byte UNKNOWN = 0; public static final byte HTML = 1; public static final byte HEAD = 2; @@ -58,8 +58,14 @@ final class HtmlTag { public static final byte EM = 31; public static final byte DFN = 32; public static final byte CITE = 33; + + public static final byte HR = 34; - public static final byte TAG_NUMBER = 34; + // mobipocket specific tags + public static final byte REFERENCE = 35; + public static final byte GUIDE = 36; + + public static final byte TAG_NUMBER = 37; private static final HashMap ourTagByName = new HashMap(256, 0.2f); private static final Byte ourUnknownTag; @@ -99,6 +105,9 @@ final class HtmlTag { ourTagByName.put("em", EM); ourTagByName.put("def", DFN); ourTagByName.put("cite", CITE); + ourTagByName.put("hr", HR); + ourTagByName.put("guide", GUIDE); + ourTagByName.put("reference", REFERENCE); } public static byte getTagByName(String name) { diff --git a/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java b/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java index e318e4563..6345b993d 100644 --- a/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java +++ b/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java @@ -21,7 +21,11 @@ package org.geometerplus.fbreader.formats.pdb; import java.io.*; +import org.geometerplus.zlibrary.core.html.ZLByteBuffer; +import org.geometerplus.zlibrary.core.html.ZLHtmlAttributeMap; + import org.geometerplus.fbreader.formats.html.HtmlReader; +import org.geometerplus.fbreader.formats.html.HtmlTag; import org.geometerplus.fbreader.bookmodel.BookModel; public class MobipocketHtmlBookReader extends HtmlReader { @@ -32,4 +36,37 @@ public class MobipocketHtmlBookReader extends HtmlReader { public InputStream getInputStream() throws IOException { return new MobipocketStream(Model.Book.File); } + + @Override + public void startElementHandler(byte tag, int offset, ZLHtmlAttributeMap attributes) { + switch (tag) { + case HtmlTag.REFERENCE: + { + System.err.println("REFERENCE"); + final ZLByteBuffer fp = attributes.getValue("filepos"); + if (fp != null) { + System.err.println(": filepos = " + fp); + } + final ZLByteBuffer title = attributes.getValue("title"); + if (title != null) { + System.err.println(": title = " + title); + } + final ZLByteBuffer type = attributes.getValue("type"); + if (type != null) { + System.err.println(": type = " + type); + } + break; + } + default: + { + //System.err.println("offset = " + offset); + final ZLByteBuffer fp = attributes.getValue("filepos"); + if (fp != null) { + System.err.println("filepos = " + fp); + } + super.startElementHandler(tag, offset, attributes); + break; + } + } + } } diff --git a/src/org/geometerplus/zlibrary/core/html/ZLHtmlParser.java b/src/org/geometerplus/zlibrary/core/html/ZLHtmlParser.java index 477ccd215..64cf01521 100644 --- a/src/org/geometerplus/zlibrary/core/html/ZLHtmlParser.java +++ b/src/org/geometerplus/zlibrary/core/html/ZLHtmlParser.java @@ -78,6 +78,8 @@ final class ZLHtmlParser { final ZLHtmlAttributeMap attributes = new ZLHtmlAttributeMap(); boolean scriptOpened = false; boolean html = false; + int bufferOffset = 0; + int offset = 0; byte state = START_DOCUMENT; while (true) { @@ -88,6 +90,7 @@ final class ZLHtmlParser { if (count < buffer.length) { buffer = ZLArrayUtils.createCopy(buffer, count, count); } + bufferOffset += count; int startPosition = 0; try { for (int i = -1;;) { @@ -98,6 +101,7 @@ mainSwitchLabel: state = LANGLE; break; case LANGLE: + offset = bufferOffset + i; switch (buffer[++i]) { case '/': state = END_TAG; @@ -182,7 +186,7 @@ mainSwitchLabel: tagName.append(buffer, startPosition, i - startPosition); { ZLByteBuffer stringTagName = unique(strings, tagName); - processStartTag(htmlReader, stringTagName, attributes); + processStartTag(htmlReader, stringTagName, offset, attributes); if (stringTagName.equalsToLCString("script")) { scriptOpened = true; state = SCRIPT; @@ -240,7 +244,7 @@ mainSwitchLabel: case '>': { ZLByteBuffer stringTagName = unique(strings, tagName); - processStartTag(htmlReader, stringTagName, attributes); + processStartTag(htmlReader, stringTagName, offset, attributes); if (stringTagName.equalsToLCString("script")) { scriptOpened = true; state = SCRIPT; @@ -359,7 +363,7 @@ mainSwitchLabel: case '>': ZLByteBuffer stringTagName = unique(strings, tagName); - processStartTag(htmlReader, stringTagName, attributes); + processStartTag(htmlReader, stringTagName, offset, attributes); if (stringTagName.equalsToLCString("script")) { scriptOpened = true; state = SCRIPT; @@ -399,7 +403,7 @@ mainSwitchLabel: case ' ': break; case '>': - processFullTag(htmlReader, unique(strings, tagName), attributes); + processFullTag(htmlReader, unique(strings, tagName), offset, attributes); state = TEXT; startPosition = i + 1; break mainSwitchLabel; @@ -464,15 +468,15 @@ mainSwitchLabel: } } - private static void processFullTag(ZLHtmlReader htmlReader, ZLByteBuffer tagName, ZLHtmlAttributeMap attributes) { + private static void processFullTag(ZLHtmlReader htmlReader, ZLByteBuffer tagName, int offset, ZLHtmlAttributeMap attributes) { String stringTagName = tagName.toString(); - htmlReader.startElementHandler(stringTagName, attributes); + htmlReader.startElementHandler(stringTagName, offset, attributes); htmlReader.endElementHandler(stringTagName); attributes.clear(); } - private static void processStartTag(ZLHtmlReader htmlReader, ZLByteBuffer tagName, ZLHtmlAttributeMap attributes) { - htmlReader.startElementHandler(tagName.toString(), attributes); + private static void processStartTag(ZLHtmlReader htmlReader, ZLByteBuffer tagName, int offset, ZLHtmlAttributeMap attributes) { + htmlReader.startElementHandler(tagName.toString(), offset, attributes); attributes.clear(); } diff --git a/src/org/geometerplus/zlibrary/core/html/ZLHtmlReader.java b/src/org/geometerplus/zlibrary/core/html/ZLHtmlReader.java index b788f9fe5..1ba32c78c 100644 --- a/src/org/geometerplus/zlibrary/core/html/ZLHtmlReader.java +++ b/src/org/geometerplus/zlibrary/core/html/ZLHtmlReader.java @@ -23,7 +23,7 @@ public interface ZLHtmlReader { public void startDocumentHandler(); public void endDocumentHandler(); - public void startElementHandler(String tag, ZLHtmlAttributeMap attributes); + public void startElementHandler(String tag, int offset, ZLHtmlAttributeMap attributes); public void endElementHandler(String tag); public void byteDataHandler(byte[] ch, int start, int length); public void entityDataHandler(String entity); diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java b/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java index e50731c87..fb94fce9e 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java @@ -19,46 +19,15 @@ package org.geometerplus.zlibrary.text.view; -final class ZLTextElementAreaVector { - private ZLTextElementArea[] myData = new ZLTextElementArea[10]; - private int myLength; - - public boolean isEmpty() { - return myLength == 0; - } - - public int size() { - return myLength; - } - - public void add(ZLTextElementArea area) { - final int index = myLength++; - if (index == myData.length) { - ZLTextElementArea[] extended = new ZLTextElementArea[2 * index]; - System.arraycopy(myData, 0, extended, 0, index); - myData = extended; - } - myData[index] = area; - } - - public void clear() { - final ZLTextElementArea[] data = myData; - for (int i = myLength - 1; i >= 0; --i) { - data[i] = null; - } - myLength = 0; - } - - ZLTextElementArea get(int index) { - return myData[index]; - } +import java.util.ArrayList; +final class ZLTextElementAreaVector extends ArrayList { ZLTextElementArea binarySearch(int x, int y) { int left = 0; - int right = myLength; + int right = size(); while (left < right) { final int middle = (left + right) / 2; - final ZLTextElementArea candidate = myData[middle]; + final ZLTextElementArea candidate = get(middle); if (candidate.YStart > y) { right = middle; } else if (candidate.YEnd < y) { diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java index 666860215..15e714769 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java @@ -19,6 +19,7 @@ package org.geometerplus.zlibrary.text.view; +import java.util.List; import java.util.ArrayList; import java.util.HashMap; @@ -232,7 +233,7 @@ public abstract class ZLTextView extends ZLTextViewBase { super.startAutoScrolling(viewPage); } - public final synchronized void onScrollingFinished(int viewPage) { + public synchronized void onScrollingFinished(int viewPage) { setScrollingActive(false); switch (viewPage) { case PAGE_CENTRAL: @@ -392,6 +393,9 @@ public abstract class ZLTextView extends ZLTextViewBase { return -1; } final ZLTextParagraphCursor paragraphCursor = cursor.getParagraphCursor(); + if (paragraphCursor == null) { + return -1; + } final int paragraphIndex = paragraphCursor.Index; int sizeOfText = myTextSize[paragraphIndex]; final int paragraphLength = paragraphCursor.getParagraphLength(); @@ -1089,6 +1093,10 @@ public abstract class ZLTextView extends ZLTextViewBase { return start; } + protected List allElements() { + return myCurrentPage.TextElementMap; + } + protected ZLTextElementArea getElementByCoordinates(int x, int y) { return myCurrentPage.TextElementMap.binarySearch(x, y); }