mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 19:42:17 +02:00
Merge branch 'master' into basket
This commit is contained in:
commit
d01ccb5f42
27 changed files with 414 additions and 569 deletions
1
TODO.internal
Normal file
1
TODO.internal
Normal file
|
@ -0,0 +1 @@
|
|||
* replace HtmlToString by android.text.Html
|
|
@ -27,6 +27,8 @@ import android.app.Activity;
|
|||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
|
@ -252,7 +254,8 @@ public class BookInfoActivity extends Activity {
|
|||
bodyView.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleView.setText(myResource.getResource("annotation").getValue());
|
||||
bodyView.setText(annotation);
|
||||
bodyView.setText(Html.fromHtml(annotation));
|
||||
bodyView.setMovementMethod(new LinkMovementMethod());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ItemsLoadingService extends Service {
|
|||
}
|
||||
|
||||
static ItemsLoader getRunnable(NetworkTree tree) {
|
||||
return (ItemsLoader)tree.getUserData(KEY);
|
||||
return tree != null ? (ItemsLoader)tree.getUserData(KEY) : null;
|
||||
}
|
||||
|
||||
private static void removeRunnable(NetworkTree tree) {
|
||||
|
|
|
@ -22,12 +22,13 @@ package org.geometerplus.android.fbreader.network;
|
|||
import java.util.*;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.geometerplus.zlibrary.ui.android.R;
|
||||
|
||||
|
@ -139,11 +140,13 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
private final void setupDescription() {
|
||||
setTextFromResource(R.id.network_book_description_title, "description");
|
||||
|
||||
String description = myBook.getSummary();
|
||||
CharSequence description = myBook.getSummary();
|
||||
if (description == null) {
|
||||
description = myResource.getResource("noDescription").getValue();
|
||||
}
|
||||
setTextById(R.id.network_book_description, description);
|
||||
final TextView descriptionView = (TextView)findViewById(R.id.network_book_description);
|
||||
descriptionView.setText(description);
|
||||
descriptionView.setMovementMethod(new LinkMovementMethod());
|
||||
}
|
||||
|
||||
private final void setupExtraLinks() {
|
||||
|
|
|
@ -95,7 +95,7 @@ public class NetworkBookItem extends NetworkItem {
|
|||
* @param urls list of urls related to this book. Can be <code>null</code>.
|
||||
*/
|
||||
public NetworkBookItem(INetworkLink link, String id, int index,
|
||||
String title, String summary, /*String language, String date,*/
|
||||
CharSequence title, CharSequence summary, /*String language, String date,*/
|
||||
List<AuthorData> authors, List<String> tags, String seriesTitle, float indexInSeries,
|
||||
UrlInfoCollection urls) {
|
||||
super(link, title, summary, urls);
|
||||
|
|
|
@ -27,15 +27,18 @@ public final class NetworkBookItemComparator implements Comparator<NetworkItem>
|
|||
final boolean item0isABook = item0 instanceof NetworkBookItem;
|
||||
final boolean item1isABook = item1 instanceof NetworkBookItem;
|
||||
|
||||
final String title0 = item0.Title.toString();
|
||||
final String title1 = item1.Title.toString();
|
||||
|
||||
if (!item0isABook && !item1isABook) {
|
||||
return item0.Title.compareTo(item1.Title);
|
||||
return title0.compareTo(title1);
|
||||
}
|
||||
if (!item0isABook || !item1isABook) {
|
||||
return item0isABook ? 1 : -1;
|
||||
}
|
||||
|
||||
final NetworkBookItem book0 = (NetworkBookItem) item0;
|
||||
final NetworkBookItem book1 = (NetworkBookItem) item1;
|
||||
final NetworkBookItem book0 = (NetworkBookItem)item0;
|
||||
final NetworkBookItem book1 = (NetworkBookItem)item1;
|
||||
|
||||
final LinkedList<NetworkBookItem.AuthorData> authors0 = book0.Authors;
|
||||
final LinkedList<NetworkBookItem.AuthorData> authors1 = book1.Authors;
|
||||
|
@ -73,11 +76,11 @@ public final class NetworkBookItemComparator implements Comparator<NetworkItem>
|
|||
return diff > 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
return book0.Title.compareTo(book1.Title);
|
||||
return title0.compareTo(title1);
|
||||
}
|
||||
|
||||
final String book0Key = book0HasSeriesTitle ? book0.SeriesTitle : book0.Title;
|
||||
final String book1Key = book1HasSeriesTitle ? book1.SeriesTitle : book1.Title;
|
||||
final String book0Key = book0HasSeriesTitle ? book0.SeriesTitle : title0;
|
||||
final String book1Key = book1HasSeriesTitle ? book1.SeriesTitle : title1;
|
||||
final int comp = book0Key.compareTo(book1Key);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
|
|
|
@ -64,7 +64,7 @@ public abstract class NetworkCatalogItem extends NetworkItem {
|
|||
* in the network library view.
|
||||
* @param flags describes how to show book items inside this catalog
|
||||
*/
|
||||
public NetworkCatalogItem(INetworkLink link, String title, String summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
public NetworkCatalogItem(INetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
super(link, title, summary, urls);
|
||||
myAccessibility = accessibility;
|
||||
Flags = flags;
|
||||
|
|
|
@ -26,9 +26,9 @@ import org.geometerplus.fbreader.network.urlInfo.UrlInfoCollection;
|
|||
|
||||
public abstract class NetworkItem {
|
||||
public final INetworkLink Link;
|
||||
public final String Title;
|
||||
public final CharSequence Title;
|
||||
|
||||
private String mySummary;
|
||||
private CharSequence mySummary;
|
||||
private final UrlInfoCollection myURLs;
|
||||
|
||||
/**
|
||||
|
@ -39,9 +39,9 @@ public abstract class NetworkItem {
|
|||
* @param summary description of this library item. Can be <code>null</code>.
|
||||
* @param urls collection of item-related urls (like icon link, opds catalog link, etc. Can be <code>null</code>.
|
||||
*/
|
||||
protected NetworkItem(INetworkLink link, String title, String summary, UrlInfoCollection urls) {
|
||||
protected NetworkItem(INetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls) {
|
||||
Link = link;
|
||||
Title = title;
|
||||
Title = title != null ? title : "";
|
||||
setSummary(summary);
|
||||
if (urls != null && !urls.isEmpty()) {
|
||||
myURLs = new UrlInfoCollection(urls);
|
||||
|
@ -50,11 +50,11 @@ public abstract class NetworkItem {
|
|||
}
|
||||
}
|
||||
|
||||
protected void setSummary(String summary) {
|
||||
protected void setSummary(CharSequence summary) {
|
||||
mySummary = summary;
|
||||
}
|
||||
|
||||
public final String getSummary() {
|
||||
public final CharSequence getSummary() {
|
||||
return mySummary;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public abstract class NetworkURLCatalogItem extends NetworkCatalogItem {
|
|||
* @param summary description of this library item. Can be <code>null</code>.
|
||||
* @param urls collection of item-related URLs. Can be <code>null</code>.
|
||||
*/
|
||||
public NetworkURLCatalogItem(INetworkLink link, String title, String summary, UrlInfoCollection urls) {
|
||||
public NetworkURLCatalogItem(INetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls) {
|
||||
this(link, title, summary, urls, Accessibility.ALWAYS, FLAGS_DEFAULT);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ public abstract class NetworkURLCatalogItem extends NetworkCatalogItem {
|
|||
* in the network library view.
|
||||
* @param flags value defines how to show book items in this catalog.
|
||||
*/
|
||||
public NetworkURLCatalogItem(INetworkLink link, String title, String summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
public NetworkURLCatalogItem(INetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
super(link, title, summary, urls, accessibility, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ public class ATOMEntry extends ATOMCommonAttributes {
|
|||
public ATOMPublished Published;
|
||||
//public String Rights; // TODO: implement ATOMTextConstruct
|
||||
//public final ATOMSource Source; // TODO: implement ATOMSource
|
||||
public String Summary; // TODO: implement ATOMTextConstruct
|
||||
public String Content; // TODO: implement ATOMContent
|
||||
public String Title; // TODO: implement ATOMTextConstruct
|
||||
public CharSequence Summary; // TODO: implement ATOMTextConstruct
|
||||
public CharSequence Content; // TODO: implement ATOMContent
|
||||
public CharSequence Title; // TODO: implement ATOMTextConstruct
|
||||
public ATOMUpdated Updated;
|
||||
|
||||
protected ATOMEntry(ZLStringMap source) {
|
||||
|
|
|
@ -34,8 +34,8 @@ public class ATOMFeedMetadata extends ATOMCommonAttributes {
|
|||
public LinkedList<ATOMLink> Links = new LinkedList<ATOMLink>();
|
||||
//public ATOMLogo Logo;
|
||||
//public String Rights; // TODO: implement ATOMTextConstruct
|
||||
public String Subtitle; // TODO: implement ATOMTextConstruct
|
||||
public String Title; // TODO: implement ATOMTextConstruct
|
||||
public CharSequence Subtitle; // TODO: implement ATOMTextConstruct
|
||||
public CharSequence Title; // TODO: implement ATOMTextConstruct
|
||||
public ATOMUpdated Updated;
|
||||
|
||||
protected ATOMFeedMetadata(ZLStringMap source) {
|
||||
|
|
|
@ -22,11 +22,10 @@ package org.geometerplus.fbreader.network.atom;
|
|||
import java.util.Map;
|
||||
|
||||
import org.geometerplus.zlibrary.core.constants.XMLNamespaces;
|
||||
import org.geometerplus.zlibrary.core.util.MimeType;
|
||||
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
||||
import org.geometerplus.zlibrary.core.xml.ZLXMLReaderAdapter;
|
||||
|
||||
import org.geometerplus.fbreader.network.opds.HtmlToString;
|
||||
|
||||
public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
||||
public static String intern(String str) {
|
||||
if (str == null || str.length() == 0) {
|
||||
|
@ -97,7 +96,7 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
|
||||
protected int myState;
|
||||
private final StringBuilder myBuffer = new StringBuilder();
|
||||
protected HtmlToString myHtmlToString = new HtmlToString();
|
||||
protected final FormattedBuffer myFormattedBuffer = new FormattedBuffer();
|
||||
protected boolean myFeedMetadataProcessed;
|
||||
|
||||
public ATOMXMLReader(ATOMFeedHandler handler, boolean readEntryNotFeed) {
|
||||
|
@ -221,11 +220,11 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
myState = F_CATEGORY;
|
||||
} else if (tag == TAG_TITLE) {
|
||||
//myTitle = new ATOMTitle(attributes); // TODO:implement ATOMTextConstruct & ATOMTitle
|
||||
myHtmlToString.setupTextContent(attributes.getValue("type"));
|
||||
setFormattingType(attributes.getValue("type"));
|
||||
myState = F_TITLE;
|
||||
} else if (tag == TAG_SUBTITLE) {
|
||||
//mySubtitle = new ATOMTitle(attributes); // TODO:implement ATOMTextConstruct & ATOMSubtitle
|
||||
myHtmlToString.setupTextContent(attributes.getValue("type"));
|
||||
setFormattingType(attributes.getValue("type"));
|
||||
myState = F_SUBTITLE;
|
||||
} else if (tag == TAG_UPDATED) {
|
||||
myUpdated = new ATOMUpdated(attributes);
|
||||
|
@ -260,15 +259,15 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
myState = FE_PUBLISHED;
|
||||
} else if (tag == TAG_SUMMARY) {
|
||||
//mySummary = new ATOMSummary(attributes); // TODO:implement ATOMTextConstruct & ATOMSummary
|
||||
myHtmlToString.setupTextContent(attributes.getValue("type"));
|
||||
setFormattingType(attributes.getValue("type"));
|
||||
myState = FE_SUMMARY;
|
||||
} else if (tag == TAG_CONTENT) {
|
||||
//myConent = new ATOMContent(attributes); // TODO:implement ATOMContent
|
||||
myHtmlToString.setupTextContent(attributes.getValue("type"));
|
||||
setFormattingType(attributes.getValue("type"));
|
||||
myState = FE_CONTENT;
|
||||
} else if (tag == TAG_TITLE) {
|
||||
//myTitle = new ATOMTitle(attributes); // TODO:implement ATOMTextConstruct & ATOMTitle
|
||||
myHtmlToString.setupTextContent(attributes.getValue("type"));
|
||||
setFormattingType(attributes.getValue("type"));
|
||||
myState = FE_TITLE;
|
||||
} else if (tag == TAG_UPDATED) {
|
||||
myUpdated = new ATOMUpdated(attributes);
|
||||
|
@ -302,7 +301,8 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
case FE_TITLE:
|
||||
case F_TITLE:
|
||||
case F_SUBTITLE:
|
||||
myHtmlToString.processTextContent(false, tag, attributes, bufferContent);
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
myFormattedBuffer.appendStartTag(tag, attributes);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -377,27 +377,29 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
}
|
||||
break;
|
||||
case F_TITLE:
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
if (ns == XMLNamespaces.Atom && tag == TAG_TITLE) {
|
||||
// TODO:implement ATOMTextConstruct & ATOMTitle
|
||||
final String title = myHtmlToString.finishTextContent(bufferContent);
|
||||
final CharSequence title = myFormattedBuffer.getText();
|
||||
if (myFeed != null) {
|
||||
myFeed.Title = title;
|
||||
}
|
||||
myState = FEED;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case F_SUBTITLE:
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
if (ns == XMLNamespaces.Atom && tag == TAG_SUBTITLE) {
|
||||
// TODO:implement ATOMTextConstruct & ATOMSubtitle
|
||||
final String subtitle = myHtmlToString.finishTextContent(bufferContent);
|
||||
final CharSequence subtitle = myFormattedBuffer.getText();
|
||||
if (myFeed != null) {
|
||||
myFeed.Subtitle = subtitle;
|
||||
}
|
||||
myState = FEED;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case F_UPDATED:
|
||||
|
@ -500,30 +502,33 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
}
|
||||
break;
|
||||
case FE_SUMMARY:
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
if (ns == XMLNamespaces.Atom && tag == TAG_SUMMARY) {
|
||||
// TODO:implement ATOMTextConstruct & ATOMSummary
|
||||
myEntry.Summary = myHtmlToString.finishTextContent(bufferContent);
|
||||
myEntry.Summary = myFormattedBuffer.getText();
|
||||
myState = F_ENTRY;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case FE_CONTENT:
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
if (ns == XMLNamespaces.Atom && tag == TAG_CONTENT) {
|
||||
// TODO:implement ATOMContent
|
||||
myEntry.Content = myHtmlToString.finishTextContent(bufferContent);
|
||||
myEntry.Content = myFormattedBuffer.getText();
|
||||
myState = F_ENTRY;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case FE_TITLE:
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
if (ns == XMLNamespaces.Atom && tag == TAG_TITLE) {
|
||||
// TODO:implement ATOMTextConstruct & ATOMTitle
|
||||
myEntry.Title = myHtmlToString.finishTextContent(bufferContent);
|
||||
myEntry.Title = myFormattedBuffer.getText();
|
||||
myState = F_ENTRY;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case FE_UPDATED:
|
||||
|
@ -543,16 +548,16 @@ public class ATOMXMLReader extends ZLXMLReaderAdapter {
|
|||
|
||||
@Override
|
||||
public final void characterDataHandler(char[] data, int start, int length) {
|
||||
final int startIndex = myBuffer.length();
|
||||
myBuffer.append(data, start, length);
|
||||
int index = startIndex;
|
||||
while ((index = myBuffer.indexOf("\r\n", index)) != -1) {
|
||||
myBuffer.replace(index, index + 2, "\n");
|
||||
}
|
||||
index = startIndex;
|
||||
while ((index = myBuffer.indexOf("\r", index)) != -1) {
|
||||
myBuffer.setCharAt(index, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
public void setFormattingType(String type) {
|
||||
if (ATOMConstants.TYPE_HTML.equals(type) || MimeType.TEXT_HTML.Name.equals(type)) {
|
||||
myFormattedBuffer.reset(FormattedBuffer.Type.Html);
|
||||
} else if (ATOMConstants.TYPE_XHTML.equals(type) || MimeType.TEXT_XHTML.Name.equals(type)) {
|
||||
myFormattedBuffer.reset(FormattedBuffer.Type.XHtml);
|
||||
} else {
|
||||
myFormattedBuffer.reset(FormattedBuffer.Type.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
100
src/org/geometerplus/fbreader/network/atom/FormattedBuffer.java
Normal file
100
src/org/geometerplus/fbreader/network/atom/FormattedBuffer.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2011 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.
|
||||
*/
|
||||
|
||||
package org.geometerplus.fbreader.network.atom;
|
||||
|
||||
import android.text.Html;
|
||||
|
||||
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
||||
|
||||
import org.geometerplus.fbreader.formats.xhtml.XHTMLReader;
|
||||
import org.geometerplus.fbreader.network.atom.ATOMConstants;
|
||||
|
||||
public class FormattedBuffer {
|
||||
public static enum Type {
|
||||
Text,
|
||||
Html,
|
||||
XHtml
|
||||
};
|
||||
|
||||
private Type myType;
|
||||
private StringBuilder myBuffer = new StringBuilder();
|
||||
|
||||
public FormattedBuffer(Type type) {
|
||||
myType = type;
|
||||
}
|
||||
|
||||
public FormattedBuffer() {
|
||||
this(Type.Text);
|
||||
}
|
||||
|
||||
public void appendText(CharSequence text) {
|
||||
if (text != null) {
|
||||
myBuffer.append(text);
|
||||
}
|
||||
}
|
||||
|
||||
public void appendText(char[] data, int start, int length) {
|
||||
myBuffer.append(data, start, length);
|
||||
}
|
||||
|
||||
public void appendStartTag(String tag, ZLStringMap attributes) {
|
||||
myBuffer.append("<").append(tag);
|
||||
for (int i = 0; i < attributes.getSize(); ++i) {
|
||||
final String key = attributes.getKey(i);
|
||||
final String value = attributes.getValue(key);
|
||||
myBuffer.append(" ").append(key).append("=\"");
|
||||
if (value != null) {
|
||||
myBuffer.append(value);
|
||||
}
|
||||
myBuffer.append("\"");
|
||||
}
|
||||
myBuffer.append(">");
|
||||
}
|
||||
|
||||
public void appendEndTag(String tag) {
|
||||
myBuffer.append("</").append(tag).append(">");
|
||||
}
|
||||
|
||||
public void reset(Type type) {
|
||||
myType = type;
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
final String text = myBuffer.toString();
|
||||
|
||||
switch (myType) {
|
||||
case Html:
|
||||
case XHtml:
|
||||
return Html.fromHtml(text);
|
||||
default:
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myBuffer.toString();
|
||||
}
|
||||
}
|
|
@ -94,7 +94,7 @@ class ByTitleCatalogItem extends SortedCatalogItem {
|
|||
protected Comparator<NetworkItem> getComparator() {
|
||||
return new Comparator<NetworkItem>() {
|
||||
public int compare(NetworkItem item0, NetworkItem item1) {
|
||||
return item0.Title.compareTo(item1.Title);
|
||||
return item0.Title.toString().compareTo(item1.Title.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ class BySeriesCatalogItem extends SortedCatalogItem {
|
|||
if (fdiff != 0) {
|
||||
return fdiff > 0 ? 1 : -1;
|
||||
}
|
||||
return book0.Title.compareTo(book1.Title);
|
||||
return book0.Title.toString().compareTo(book1.Title.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ class BySeriesCatalogItem extends SortedCatalogItem {
|
|||
public class LitResBookshelfItem extends NetworkURLCatalogItem {
|
||||
private boolean myForceReload;
|
||||
|
||||
public LitResBookshelfItem(INetworkLink link, String title, String summary, UrlInfoCollection urls, Accessibility accessibility) {
|
||||
public LitResBookshelfItem(INetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Accessibility accessibility) {
|
||||
super(link, title, summary, urls, accessibility, FLAGS_DEFAULT);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.geometerplus.fbreader.network.opds.OPDSNetworkLink;
|
|||
import org.geometerplus.fbreader.network.urlInfo.*;
|
||||
|
||||
public class LitResRecommendationsItem extends OPDSCatalogItem {
|
||||
public LitResRecommendationsItem(OPDSNetworkLink link, String title, String summary, UrlInfoCollection urls, Accessibility accessibility) {
|
||||
public LitResRecommendationsItem(OPDSNetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Accessibility accessibility) {
|
||||
super(link, title, summary, urls, accessibility, FLAGS_DEFAULT & ~FLAGS_GROUP);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.geometerplus.zlibrary.core.util.MimeType;
|
|||
import org.geometerplus.zlibrary.core.xml.*;
|
||||
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.opds.HtmlToString;
|
||||
import org.geometerplus.fbreader.network.atom.FormattedBuffer;
|
||||
import org.geometerplus.fbreader.network.urlInfo.*;
|
||||
|
||||
class LitResXMLReader extends LitResAuthenticationXMLReader {
|
||||
|
@ -41,7 +41,7 @@ class LitResXMLReader extends LitResAuthenticationXMLReader {
|
|||
private String mySeriesTitle;
|
||||
private int myIndexInSeries;
|
||||
|
||||
private String mySummary;
|
||||
private CharSequence mySummary;
|
||||
|
||||
private final UrlInfoCollection myUrls = new UrlInfoCollection();
|
||||
|
||||
|
@ -93,99 +93,92 @@ class LitResXMLReader extends LitResAuthenticationXMLReader {
|
|||
|
||||
private int myState = START;
|
||||
private final StringBuilder myBuffer = new StringBuilder();
|
||||
private HtmlToString myHtmlToString = new HtmlToString();
|
||||
private FormattedBuffer myAnnotationBuffer = new FormattedBuffer(FormattedBuffer.Type.XHtml);
|
||||
|
||||
@Override
|
||||
public boolean startElementHandler(String tag, ZLStringMap attributes) {
|
||||
tag = tag.intern();
|
||||
|
||||
final char[] bufferContentArray = myBuffer.toString().trim().toCharArray();
|
||||
final String bufferContent;
|
||||
if (bufferContentArray.length == 0) {
|
||||
bufferContent = null;
|
||||
} else {
|
||||
bufferContent = new String(bufferContentArray);
|
||||
}
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
|
||||
switch(myState) {
|
||||
case START:
|
||||
if (TAG_CATALOG == tag) {
|
||||
myState = CATALOG;
|
||||
}
|
||||
break;
|
||||
case CATALOG:
|
||||
if (TAG_BOOK == tag) {
|
||||
myBookId = attributes.getValue("hub_id");
|
||||
myUrls.addInfo(new UrlInfo(
|
||||
UrlInfo.Type.Image, attributes.getValue("cover_preview")
|
||||
));
|
||||
|
||||
myUrls.addInfo(new BookUrlInfo(
|
||||
UrlInfo.Type.BookConditional,
|
||||
BookUrlInfo.Format.FB2_ZIP,
|
||||
"https://robot.litres.ru/pages/catalit_download_book/?art=" + myBookId
|
||||
));
|
||||
myState = BOOK;
|
||||
}
|
||||
break;
|
||||
case BOOK:
|
||||
if (TAG_TEXT_DESCRIPTION == tag) {
|
||||
myState = BOOK_DESCRIPTION;
|
||||
}
|
||||
break;
|
||||
case BOOK_DESCRIPTION:
|
||||
if (TAG_HIDDEN == tag) {
|
||||
myState = HIDDEN;
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
if (TAG_TITLE_INFO == tag) {
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case TITLE_INFO:
|
||||
if (TAG_GENRE == tag) {
|
||||
myState = GENRE;
|
||||
} else if (TAG_AUTHOR == tag) {
|
||||
myState = AUTHOR;
|
||||
} else if (TAG_BOOK_TITLE == tag) {
|
||||
myState = BOOK_TITLE;
|
||||
} else if (TAG_ANNOTATION == tag) {
|
||||
myHtmlToString.setupTextContent(MimeType.TEXT_XHTML.Name);
|
||||
myState = ANNOTATION;
|
||||
} else if (TAG_DATE == tag) {
|
||||
myState = DATE;
|
||||
} else if (TAG_LANGUAGE == tag) {
|
||||
myState = LANGUAGE;
|
||||
} else if (TAG_SEQUENCE == tag) {
|
||||
mySeriesTitle = attributes.getValue("name");
|
||||
if (mySeriesTitle != null) {
|
||||
myIndexInSeries = 0;
|
||||
final String indexInSeries = attributes.getValue("number");
|
||||
if (indexInSeries != null) {
|
||||
try {
|
||||
myIndexInSeries = Integer.parseInt(indexInSeries);
|
||||
} catch (NumberFormatException e) {
|
||||
switch (myState) {
|
||||
case START:
|
||||
if (TAG_CATALOG == tag) {
|
||||
myState = CATALOG;
|
||||
}
|
||||
break;
|
||||
case CATALOG:
|
||||
if (TAG_BOOK == tag) {
|
||||
myBookId = attributes.getValue("hub_id");
|
||||
myUrls.addInfo(new UrlInfo(
|
||||
UrlInfo.Type.Image, attributes.getValue("cover_preview")
|
||||
));
|
||||
|
||||
myUrls.addInfo(new BookUrlInfo(
|
||||
UrlInfo.Type.BookConditional,
|
||||
BookUrlInfo.Format.FB2_ZIP,
|
||||
"https://robot.litres.ru/pages/catalit_download_book/?art=" + myBookId
|
||||
));
|
||||
myState = BOOK;
|
||||
}
|
||||
break;
|
||||
case BOOK:
|
||||
if (TAG_TEXT_DESCRIPTION == tag) {
|
||||
myState = BOOK_DESCRIPTION;
|
||||
}
|
||||
break;
|
||||
case BOOK_DESCRIPTION:
|
||||
if (TAG_HIDDEN == tag) {
|
||||
myState = HIDDEN;
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
if (TAG_TITLE_INFO == tag) {
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case TITLE_INFO:
|
||||
if (TAG_GENRE == tag) {
|
||||
myState = GENRE;
|
||||
} else if (TAG_AUTHOR == tag) {
|
||||
myState = AUTHOR;
|
||||
} else if (TAG_BOOK_TITLE == tag) {
|
||||
myState = BOOK_TITLE;
|
||||
} else if (TAG_ANNOTATION == tag) {
|
||||
myState = ANNOTATION;
|
||||
} else if (TAG_DATE == tag) {
|
||||
myState = DATE;
|
||||
} else if (TAG_LANGUAGE == tag) {
|
||||
myState = LANGUAGE;
|
||||
} else if (TAG_SEQUENCE == tag) {
|
||||
mySeriesTitle = attributes.getValue("name");
|
||||
if (mySeriesTitle != null) {
|
||||
myIndexInSeries = 0;
|
||||
final String indexInSeries = attributes.getValue("number");
|
||||
if (indexInSeries != null) {
|
||||
try {
|
||||
myIndexInSeries = Integer.parseInt(indexInSeries);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
//myState = SEQUENCE; // handled through attributes without state
|
||||
}
|
||||
//myState = SEQUENCE; // handled through attributes without state
|
||||
}
|
||||
break;
|
||||
case AUTHOR:
|
||||
if (TAG_FIRST_NAME == tag) {
|
||||
myState = FIRST_NAME;
|
||||
} else if (TAG_MIDDLE_NAME == tag) {
|
||||
myState = MIDDLE_NAME;
|
||||
} else if (TAG_LAST_NAME == tag) {
|
||||
myState = LAST_NAME;
|
||||
}
|
||||
break;
|
||||
case ANNOTATION:
|
||||
myHtmlToString.processTextContent(false, tag, attributes, bufferContent);
|
||||
break;
|
||||
break;
|
||||
case AUTHOR:
|
||||
if (TAG_FIRST_NAME == tag) {
|
||||
myState = FIRST_NAME;
|
||||
} else if (TAG_MIDDLE_NAME == tag) {
|
||||
myState = MIDDLE_NAME;
|
||||
} else if (TAG_LAST_NAME == tag) {
|
||||
myState = LAST_NAME;
|
||||
}
|
||||
break;
|
||||
case ANNOTATION:
|
||||
myAnnotationBuffer.appendText(myBuffer);
|
||||
myAnnotationBuffer.appendStartTag(tag, attributes);
|
||||
break;
|
||||
}
|
||||
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -194,145 +187,141 @@ class LitResXMLReader extends LitResAuthenticationXMLReader {
|
|||
public boolean endElementHandler(String tag) {
|
||||
tag = tag.intern();
|
||||
|
||||
final char[] bufferContentArray = myBuffer.toString().trim().toCharArray();
|
||||
final String bufferContent;
|
||||
if (bufferContentArray.length == 0) {
|
||||
bufferContent = null;
|
||||
} else {
|
||||
bufferContent = new String(bufferContentArray);
|
||||
}
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
|
||||
switch (myState) {
|
||||
case CATALOG:
|
||||
if (TAG_CATALOG == tag) {
|
||||
myState = START;
|
||||
}
|
||||
break;
|
||||
case BOOK:
|
||||
if (TAG_BOOK == tag) {
|
||||
|
||||
Books.add(new NetworkBookItem(
|
||||
Link,
|
||||
myBookId,
|
||||
myIndex++,
|
||||
myTitle,
|
||||
mySummary,
|
||||
//myLanguage,
|
||||
//myDate,
|
||||
myAuthors,
|
||||
myTags,
|
||||
mySeriesTitle,
|
||||
myIndexInSeries,
|
||||
myUrls
|
||||
));
|
||||
|
||||
myBookId = myTitle = /*myLanguage = myDate = */mySeriesTitle = mySummary = null;
|
||||
myIndexInSeries = 0;
|
||||
myAuthors.clear();
|
||||
myTags.clear();
|
||||
myUrls.clear();
|
||||
myState = CATALOG;
|
||||
}
|
||||
break;
|
||||
case BOOK_DESCRIPTION:
|
||||
if (TAG_TEXT_DESCRIPTION == tag) {
|
||||
myState = BOOK;
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
if (TAG_HIDDEN == tag) {
|
||||
myState = BOOK_DESCRIPTION;
|
||||
}
|
||||
break;
|
||||
case TITLE_INFO:
|
||||
if (TAG_TITLE_INFO == tag) {
|
||||
myState = HIDDEN;
|
||||
}
|
||||
break;
|
||||
case AUTHOR:
|
||||
if (TAG_AUTHOR == tag) {
|
||||
StringBuilder displayName = new StringBuilder();
|
||||
if (myAuthorFirstName != null) {
|
||||
displayName.append(myAuthorFirstName).append(" ");
|
||||
case CATALOG:
|
||||
if (TAG_CATALOG == tag) {
|
||||
myState = START;
|
||||
}
|
||||
if (myAuthorMiddleName != null) {
|
||||
displayName.append(myAuthorMiddleName).append(" ");
|
||||
break;
|
||||
case BOOK:
|
||||
if (TAG_BOOK == tag) {
|
||||
|
||||
Books.add(new NetworkBookItem(
|
||||
Link,
|
||||
myBookId,
|
||||
myIndex++,
|
||||
myTitle,
|
||||
mySummary,
|
||||
//myLanguage,
|
||||
//myDate,
|
||||
myAuthors,
|
||||
myTags,
|
||||
mySeriesTitle,
|
||||
myIndexInSeries,
|
||||
myUrls
|
||||
));
|
||||
|
||||
myBookId = myTitle = /*myLanguage = myDate = */mySeriesTitle = null;
|
||||
mySummary = null;
|
||||
myIndexInSeries = 0;
|
||||
myAuthors.clear();
|
||||
myTags.clear();
|
||||
myUrls.clear();
|
||||
myState = CATALOG;
|
||||
}
|
||||
if (myAuthorLastName != null) {
|
||||
displayName.append(myAuthorLastName).append(" ");
|
||||
break;
|
||||
case BOOK_DESCRIPTION:
|
||||
if (TAG_TEXT_DESCRIPTION == tag) {
|
||||
myState = BOOK;
|
||||
}
|
||||
myAuthors.add(new NetworkBookItem.AuthorData(displayName.toString().trim(), myAuthorLastName));
|
||||
myAuthorFirstName = null;
|
||||
myAuthorMiddleName = null;
|
||||
myAuthorLastName = null;
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case FIRST_NAME:
|
||||
if (TAG_FIRST_NAME == tag) {
|
||||
myAuthorFirstName = bufferContent;
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case MIDDLE_NAME:
|
||||
if (TAG_MIDDLE_NAME == tag) {
|
||||
myAuthorMiddleName = bufferContent;
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case LAST_NAME:
|
||||
if (TAG_LAST_NAME == tag) {
|
||||
myAuthorLastName = bufferContent;
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case GENRE:
|
||||
if (TAG_GENRE == tag) {
|
||||
/*if (bufferContent != null) {
|
||||
const std::map<std::string,shared_ptr<LitResGenre> > &genresMap =
|
||||
LitResGenreMap::Instance().genresMap();
|
||||
const std::map<shared_ptr<LitResGenre>,std::string> &genresTitles =
|
||||
LitResGenreMap::Instance().genresTitles();
|
||||
|
||||
std::map<std::string, shared_ptr<LitResGenre> >::const_iterator it = genresMap.find(bufferContent);
|
||||
if (it != genresMap.end()) {
|
||||
std::map<shared_ptr<LitResGenre>, std::string>::const_iterator jt = genresTitles.find(it->second);
|
||||
if (jt != genresTitles.end()) {
|
||||
myTags.push_back(jt->second);
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
if (TAG_HIDDEN == tag) {
|
||||
myState = BOOK_DESCRIPTION;
|
||||
}
|
||||
break;
|
||||
case TITLE_INFO:
|
||||
if (TAG_TITLE_INFO == tag) {
|
||||
myState = HIDDEN;
|
||||
}
|
||||
break;
|
||||
case AUTHOR:
|
||||
if (TAG_AUTHOR == tag) {
|
||||
StringBuilder displayName = new StringBuilder();
|
||||
if (myAuthorFirstName != null) {
|
||||
displayName.append(myAuthorFirstName).append(" ");
|
||||
}
|
||||
}*/
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case BOOK_TITLE:
|
||||
if (TAG_BOOK_TITLE == tag) {
|
||||
myTitle = bufferContent;
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case ANNOTATION:
|
||||
if (TAG_ANNOTATION == tag) {
|
||||
mySummary = myHtmlToString.finishTextContent(bufferContent);
|
||||
myState = TITLE_INFO;
|
||||
} else {
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
}
|
||||
break;
|
||||
case DATE:
|
||||
if (TAG_DATE == tag) {
|
||||
//myDate = bufferContent;
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case LANGUAGE:
|
||||
if (TAG_LANGUAGE == tag) {
|
||||
//myLanguage = bufferContent;
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
if (myAuthorMiddleName != null) {
|
||||
displayName.append(myAuthorMiddleName).append(" ");
|
||||
}
|
||||
if (myAuthorLastName != null) {
|
||||
displayName.append(myAuthorLastName).append(" ");
|
||||
}
|
||||
myAuthors.add(new NetworkBookItem.AuthorData(displayName.toString().trim(), myAuthorLastName));
|
||||
myAuthorFirstName = null;
|
||||
myAuthorMiddleName = null;
|
||||
myAuthorLastName = null;
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case FIRST_NAME:
|
||||
if (TAG_FIRST_NAME == tag) {
|
||||
myAuthorFirstName = myBuffer.toString();
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case MIDDLE_NAME:
|
||||
if (TAG_MIDDLE_NAME == tag) {
|
||||
myAuthorMiddleName = myBuffer.toString();
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case LAST_NAME:
|
||||
if (TAG_LAST_NAME == tag) {
|
||||
myAuthorLastName = myBuffer.toString();
|
||||
myState = AUTHOR;
|
||||
}
|
||||
break;
|
||||
case GENRE:
|
||||
if (TAG_GENRE == tag) {
|
||||
/*if (myBuffer.length() != 0) {
|
||||
const std::map<std::string,shared_ptr<LitResGenre> > &genresMap =
|
||||
LitResGenreMap::Instance().genresMap();
|
||||
const std::map<shared_ptr<LitResGenre>,std::string> &genresTitles =
|
||||
LitResGenreMap::Instance().genresTitles();
|
||||
|
||||
std::map<std::string, shared_ptr<LitResGenre> >::const_iterator it = genresMap.find(myBuffer);
|
||||
if (it != genresMap.end()) {
|
||||
std::map<shared_ptr<LitResGenre>, std::string>::const_iterator jt = genresTitles.find(it->second);
|
||||
if (jt != genresTitles.end()) {
|
||||
myTags.push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case BOOK_TITLE:
|
||||
if (TAG_BOOK_TITLE == tag) {
|
||||
myTitle = myBuffer.toString();
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case ANNOTATION:
|
||||
myAnnotationBuffer.appendText(myBuffer);
|
||||
if (TAG_ANNOTATION == tag) {
|
||||
mySummary = myAnnotationBuffer.getText();
|
||||
myAnnotationBuffer.reset();
|
||||
myState = TITLE_INFO;
|
||||
} else {
|
||||
myAnnotationBuffer.appendEndTag(tag);
|
||||
}
|
||||
break;
|
||||
case DATE:
|
||||
if (TAG_DATE == tag) {
|
||||
//myDate = myBuffer.toString();
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
case LANGUAGE:
|
||||
if (TAG_LANGUAGE == tag) {
|
||||
//myLanguage = myBuffer.toString();
|
||||
myState = TITLE_INFO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2011 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.
|
||||
*/
|
||||
|
||||
package org.geometerplus.fbreader.network.opds;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.geometerplus.zlibrary.core.html.*;
|
||||
import org.geometerplus.zlibrary.core.util.MimeType;
|
||||
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessor;
|
||||
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
||||
|
||||
import org.geometerplus.fbreader.formats.xhtml.XHTMLReader;
|
||||
import org.geometerplus.fbreader.network.atom.ATOMConstants;
|
||||
|
||||
public class HtmlToString {
|
||||
private String myLastOpenedTag;
|
||||
private String myTextType;
|
||||
private StringBuilder myTextContent = new StringBuilder();
|
||||
|
||||
private HtmlToStringReader myHtmlToStringReader = new HtmlToStringReader();
|
||||
|
||||
public void setupTextContent(String type) {
|
||||
if (type == null) {
|
||||
myTextType = ATOMConstants.TYPE_DEFAULT;
|
||||
} else {
|
||||
myTextType = type;
|
||||
}
|
||||
myTextContent.delete(0, myTextContent.length());
|
||||
}
|
||||
|
||||
public String finishTextContent(String bufferContent) {
|
||||
if (bufferContent != null) {
|
||||
myTextContent.append(bufferContent);
|
||||
}
|
||||
char[] contentArray = myTextContent.toString().trim().toCharArray();
|
||||
String result;
|
||||
if (contentArray.length == 0) {
|
||||
result = null;
|
||||
} else {
|
||||
result = new String(contentArray);
|
||||
}
|
||||
if (result != null) {
|
||||
if (ATOMConstants.TYPE_HTML.equals(myTextType) ||
|
||||
ATOMConstants.TYPE_XHTML.equals(myTextType) ||
|
||||
MimeType.TEXT_HTML.Name.equals(myTextType) ||
|
||||
MimeType.TEXT_XHTML.Name.equals(myTextType)) {
|
||||
myHtmlToStringReader.readFromString(result);
|
||||
result = myHtmlToStringReader.getString();
|
||||
}
|
||||
}
|
||||
myTextType = null;
|
||||
myTextContent.delete(0, myTextContent.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void processTextContent(boolean closeTag, String tag, ZLStringMap attributes, String bufferContent) {
|
||||
if (ATOMConstants.TYPE_XHTML.equals(myTextType) ||
|
||||
MimeType.TEXT_XHTML.Name.equals(myTextType)) {
|
||||
if (bufferContent != null) {
|
||||
myTextContent.append(bufferContent);
|
||||
}
|
||||
if (closeTag) {
|
||||
final int index = myTextContent.length() - 1;
|
||||
if (tag == myLastOpenedTag && bufferContent == null && myTextContent.charAt(index) == '>') {
|
||||
myTextContent.insert(index, '/'); // TODO: Is it necessary in HTML???????
|
||||
} else {
|
||||
myTextContent.append("</").append(tag).append(">");
|
||||
}
|
||||
myLastOpenedTag = null;
|
||||
} else {
|
||||
myLastOpenedTag = tag;
|
||||
StringBuilder buffer = new StringBuilder("<").append(tag);
|
||||
for (int i = 0; i < attributes.getSize(); ++i) {
|
||||
final String key = attributes.getKey(i);
|
||||
final String value = attributes.getValue(key);
|
||||
buffer.append(" ").append(key).append("=\"");
|
||||
if (value != null) {
|
||||
buffer.append(value);
|
||||
}
|
||||
buffer.append("\"");
|
||||
}
|
||||
buffer.append(" >");
|
||||
myTextContent.append(buffer.toString());
|
||||
}
|
||||
} else {
|
||||
if (bufferContent != null) {
|
||||
myTextContent.append(bufferContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class HtmlToStringReader implements ZLHtmlReader {
|
||||
|
||||
private StringBuilder myBuffer = new StringBuilder();
|
||||
private byte[] myByteData;
|
||||
private int myByteDataLength;
|
||||
private HashMap<String,char[]> myEntityMap;
|
||||
|
||||
public void readFromString(String htmlString) {
|
||||
final StringBuilder html = new StringBuilder();
|
||||
html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
|
||||
.append("<html><head>")
|
||||
.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />")
|
||||
.append("<title></title>")
|
||||
.append("</head><body>")
|
||||
.append(htmlString)
|
||||
.append("</body></html>");
|
||||
final byte[] bytes;
|
||||
try {
|
||||
bytes = html.toString().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new RuntimeException("It's impossible!!! UTF-8 charset is not supported!!!", ex);
|
||||
}
|
||||
ZLHtmlProcessor.read(this, new ByteArrayInputStream(bytes));
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return new String(myBuffer.toString().trim().toCharArray());
|
||||
}
|
||||
|
||||
|
||||
public void startDocumentHandler() {
|
||||
myBuffer.delete(0, myBuffer.length());
|
||||
myByteDataLength = 0;
|
||||
}
|
||||
|
||||
public void endDocumentHandler() {
|
||||
processByteData();
|
||||
}
|
||||
|
||||
public void startElementHandler(String tag, int offset, ZLHtmlAttributeMap attributes) {
|
||||
processByteData();
|
||||
tag = tag.toLowerCase().intern();
|
||||
if (tag == "br") {
|
||||
if (myBuffer.length() > 0) {
|
||||
myBuffer.append('\n');
|
||||
}
|
||||
} else if (tag == "hr") {
|
||||
if (myBuffer.length() > 0) {
|
||||
if (myBuffer.charAt(myBuffer.length() - 1) != '\n') {
|
||||
myBuffer.append('\n');
|
||||
}
|
||||
myBuffer.append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void endElementHandler(String tag) {
|
||||
processByteData();
|
||||
tag = tag.toLowerCase().intern();
|
||||
if (tag == "p") {
|
||||
if (myBuffer.length() > 0) {
|
||||
myBuffer.append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processByteData() {
|
||||
if (myByteDataLength == 0) {
|
||||
return;
|
||||
}
|
||||
final String data;
|
||||
try {
|
||||
data = new String(myByteData, 0, myByteDataLength, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new RuntimeException("It's impossible!!! UTF-8 charset is not supported!!!", ex);
|
||||
}
|
||||
myByteDataLength = 0;
|
||||
if (data.length() == 0) {
|
||||
return;
|
||||
}
|
||||
if (myBuffer.length() > 0 && !Character.isWhitespace(myBuffer.charAt(myBuffer.length() - 1))) {
|
||||
myBuffer.append(' ');
|
||||
}
|
||||
int index = 0;
|
||||
while (index < data.length() && Character.isWhitespace(data.charAt(index))) {
|
||||
++index;
|
||||
}
|
||||
boolean lastSpace = false;
|
||||
while (index < data.length()) {
|
||||
final char ch = data.charAt(index++);
|
||||
if (Character.isWhitespace(ch)) {
|
||||
lastSpace = true;
|
||||
} else {
|
||||
if (lastSpace) {
|
||||
myBuffer.append(' ');
|
||||
lastSpace = false;
|
||||
}
|
||||
myBuffer.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void entityDataHandler(String entity) {
|
||||
processByteData();
|
||||
|
||||
if (entity.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (myEntityMap == null) {
|
||||
myEntityMap = new HashMap<String,char[]>(ZLXMLProcessor.getEntityMap(XHTMLReader.xhtmlDTDs()));
|
||||
}
|
||||
char[] data = myEntityMap.get(entity);
|
||||
if (data == null) {
|
||||
if (entity.charAt(0) == '#') {
|
||||
try {
|
||||
int number;
|
||||
if (entity.charAt(1) == 'x') {
|
||||
number = Integer.parseInt(entity.substring(2), 16);
|
||||
} else {
|
||||
number = Integer.parseInt(entity.substring(1));
|
||||
}
|
||||
data = new char[] { (char)number };
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
if (data == null) {
|
||||
data = new char[0];
|
||||
}
|
||||
myEntityMap.put(entity, data);
|
||||
}
|
||||
//System.err.println("FBREADER -- ENTITY: &" + entity + "; --> " + new String(data));
|
||||
myBuffer.append(data);
|
||||
}
|
||||
|
||||
public void byteDataHandler(byte[] data, int start, int length) {
|
||||
if (length <= 0) {
|
||||
return;
|
||||
}
|
||||
if (myByteData == null) {
|
||||
myByteData = new byte[length];
|
||||
System.arraycopy(data, start, myByteData, 0, length);
|
||||
myByteDataLength = length;
|
||||
} else {
|
||||
if (myByteData.length < myByteDataLength + length) {
|
||||
final byte[] oldData = myByteData;
|
||||
myByteData = new byte[myByteDataLength + length];
|
||||
System.arraycopy(oldData, 0, myByteData, 0, myByteDataLength);
|
||||
}
|
||||
System.arraycopy(data, start, myByteData, myByteDataLength, length);
|
||||
myByteDataLength += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import org.geometerplus.fbreader.network.atom.*;
|
|||
import org.geometerplus.fbreader.network.urlInfo.*;
|
||||
|
||||
public class OPDSBookItem extends NetworkBookItem implements OPDSConstants {
|
||||
private static String getAnnotation(OPDSEntry entry) {
|
||||
private static CharSequence getAnnotation(OPDSEntry entry) {
|
||||
if (entry.Content != null) {
|
||||
return entry.Content;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ public class OPDSBookItem extends NetworkBookItem implements OPDSConstants {
|
|||
|
||||
public boolean processFeedEntry(OPDSEntry entry) {
|
||||
addUrls(getUrls((OPDSNetworkLink)Link, entry, myUrl));
|
||||
final String summary = getAnnotation(entry);
|
||||
final CharSequence summary = getAnnotation(entry);
|
||||
if (summary != null) {
|
||||
setSummary(summary);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ import org.geometerplus.fbreader.network.atom.ATOMFeedHandler;
|
|||
class OPDSCatalogInfoHandler implements ATOMFeedHandler<OPDSFeedMetadata,OPDSEntry> {
|
||||
public boolean FeedStarted;
|
||||
public String Icon;
|
||||
public String Title;
|
||||
public String Summary;
|
||||
public CharSequence Title;
|
||||
public CharSequence Summary;
|
||||
|
||||
public OpenSearchDescription DirectOpenSearchDescription;
|
||||
private final List<String> myOpensearchDescriptionURLs;
|
||||
|
|
|
@ -39,12 +39,12 @@ public class OPDSCatalogItem extends NetworkURLCatalogItem {
|
|||
private State myLoadingState;
|
||||
private final Map<String,String> myExtraData;
|
||||
|
||||
OPDSCatalogItem(OPDSNetworkLink link, String title, String summary, UrlInfoCollection urls, Map<String,String> extraData) {
|
||||
OPDSCatalogItem(OPDSNetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Map<String,String> extraData) {
|
||||
super(link, title, summary, urls);
|
||||
myExtraData = extraData;
|
||||
}
|
||||
|
||||
protected OPDSCatalogItem(OPDSNetworkLink link, String title, String summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
protected OPDSCatalogItem(OPDSNetworkLink link, CharSequence title, CharSequence summary, UrlInfoCollection urls, Accessibility accessibility, int flags) {
|
||||
super(link, title, summary, urls, accessibility, flags);
|
||||
myExtraData = null;
|
||||
}
|
||||
|
|
|
@ -130,8 +130,8 @@ public class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLin
|
|||
descriptions.add(info.DirectOpenSearchDescription);
|
||||
}
|
||||
if (!urlsOnly) {
|
||||
myTitle = info.Title;
|
||||
mySummary = info.Summary;
|
||||
myTitle = info.Title.toString();
|
||||
mySummary = info.Summary != null ? info.Summary.toString() : null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -242,11 +242,11 @@ class OPDSFeedHandler implements ATOMFeedHandler<OPDSFeedMetadata,OPDSEntry>, OP
|
|||
urlMap.removeAllInfos(UrlInfo.Type.HtmlPage);
|
||||
}
|
||||
|
||||
final String annotation;
|
||||
final CharSequence annotation;
|
||||
if (entry.Summary != null) {
|
||||
annotation = entry.Summary.replace("\n", "");
|
||||
annotation = entry.Summary;
|
||||
} else if (entry.Content != null) {
|
||||
annotation = entry.Content.replace("\n", "");
|
||||
annotation = entry.Content;
|
||||
} else {
|
||||
annotation = null;
|
||||
}
|
||||
|
|
|
@ -92,8 +92,8 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants {
|
|||
return false;
|
||||
}
|
||||
final String siteName = id.substring(ENTRY_ID_PREFIX.length());
|
||||
final String title = entry.Title;
|
||||
final String summary = entry.Content;
|
||||
final CharSequence title = entry.Title;
|
||||
final CharSequence summary = entry.Content;
|
||||
final String language = entry.DCLanguage;
|
||||
|
||||
final UrlInfoCollection<UrlInfoWithDate> infos =
|
||||
|
@ -160,8 +160,8 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants {
|
|||
|
||||
private INetworkLink link(
|
||||
String siteName,
|
||||
String title,
|
||||
String summary,
|
||||
CharSequence title,
|
||||
CharSequence summary,
|
||||
String language,
|
||||
UrlInfoCollection<UrlInfoWithDate> infos,
|
||||
HashMap<String,NetworkCatalogItem.Accessibility> urlConditions,
|
||||
|
@ -171,10 +171,13 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants {
|
|||
return null;
|
||||
}
|
||||
|
||||
final String titleString = title.toString();
|
||||
final String summaryString = summary != null ? summary.toString() : null;
|
||||
|
||||
OPDSNetworkLink opdsLink = new OPDSNetworkLink(
|
||||
siteName,
|
||||
title,
|
||||
summary,
|
||||
titleString,
|
||||
summaryString,
|
||||
language,
|
||||
infos,
|
||||
myHasStableIdentifiers
|
||||
|
|
|
@ -137,7 +137,8 @@ public class OPDSXMLReader extends ATOMXMLReader {
|
|||
}
|
||||
break;
|
||||
case FE_CONTENT:
|
||||
myHtmlToString.processTextContent(false, tag, attributes, bufferContent);
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
myFormattedBuffer.appendStartTag(tag, attributes);
|
||||
// FIXME: HACK: html handling must be implemeted neatly
|
||||
if (tag == TAG_HACK_SPAN || attributes.getValue("class") == "price") {
|
||||
myState = FEC_HACK_SPAN;
|
||||
|
@ -173,7 +174,9 @@ public class OPDSXMLReader extends ATOMXMLReader {
|
|||
break;
|
||||
case FEC_HACK_SPAN:
|
||||
// FIXME: HACK
|
||||
myHtmlToString.processTextContent(true, tag, null, bufferContent);
|
||||
myFormattedBuffer.appendText(bufferContent);
|
||||
myFormattedBuffer.appendEndTag(tag);
|
||||
myFormattedBuffer.appendText("<br/>");
|
||||
if (bufferContent != null) {
|
||||
getOPDSEntry().addAttribute(KEY_PRICE, bufferContent.intern());
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class NetworkBookTree extends NetworkTree {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Book.Title;
|
||||
return Book.Title.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,13 +44,13 @@ public class NetworkCatalogTree extends NetworkTree {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Item.Title;
|
||||
return Item.Title.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSummary() {
|
||||
final String summary = Item.getSummary();
|
||||
return summary != null ? summary : "";
|
||||
final CharSequence summary = Item.getSummary();
|
||||
return summary != null ? summary.toString() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,7 +36,7 @@ public class TopUpTree extends NetworkTree {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Item.Title;
|
||||
return Item.Title.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,9 +45,9 @@ public class TopUpTree extends NetworkTree {
|
|||
try {
|
||||
if (mgr.isAuthorised(false)) {
|
||||
final String account = mgr.currentAccount();
|
||||
final String summary = Item.getSummary();
|
||||
final CharSequence summary = Item.getSummary();
|
||||
if (account != null && summary != null) {
|
||||
return summary.replace("%s", account);
|
||||
return summary.toString().replace("%s", account);
|
||||
}
|
||||
}
|
||||
} catch (ZLNetworkException e) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue