1
0
Fork 0
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:
Nikolay Pultsin 2011-05-08 03:11:17 +01:00
commit d01ccb5f42
27 changed files with 414 additions and 569 deletions

1
TODO.internal Normal file
View file

@ -0,0 +1 @@
* replace HtmlToString by android.text.Html

View file

@ -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());
}
}

View file

@ -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) {

View file

@ -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() {

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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);
}
}
}

View 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();
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}
}
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}
}
});

View file

@ -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;
}

View file

@ -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

View file

@ -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());
}

View file

@ -44,7 +44,7 @@ public class NetworkBookTree extends NetworkTree {
@Override
public String getName() {
return Book.Title;
return Book.Title.toString();
}
@Override

View file

@ -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

View file

@ -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) {