1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 02:39:23 +02:00

New OPDS.XML DTD and Catalog loading changes

git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1619 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
Vasiliy Bout 2010-07-26 13:13:57 +00:00
parent a2719f033b
commit 903eded8f7
25 changed files with 250 additions and 31 deletions

View file

@ -10,8 +10,7 @@ DONE сделать SeekBar (как в ветке alex) в пункте Navigate
DONE каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен: DONE каталог должен иметь не 2 состояния (загружен/не загружен), а загружен полностью/не полностью/не загружен:
в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг) в случае загрузки "не полностью" при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что поделены на куски по 20 книг)
** по-умолчанию сделать отбрасывание элементов недогруженных страниц DONE по-умолчанию сделать отбрасывание элементов недогруженных страниц (плюс свойство OPDSLink'ов hasStableIdentifiers)
(плюс свойство OPDSLink'ов, подтверждающее стабильность идентификаторов)
* 3 иконки в верхнем-правом углу для книжек * 3 иконки в верхнем-правом углу для книжек
DONE регистрация новых пользователей -- в диалоге authentication DONE регистрация новых пользователей -- в диалоге authentication

56
data/network/catalog.dtd Normal file
View file

@ -0,0 +1,56 @@
<!ELEMENT catalog (site,title,summary?,link+,advancedSearch?,relationAliases?,feeds?,authentication?,urlRewritingRules?,icon)>
<!ATTLIST catalog
type (opds) #REQUIRED
hasStableIdentifiers (true|false) "false"
>
<!ELEMENT site (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT summary (#PCDATA)>
<!ELEMENT icon (#PCDATA)>
<!ELEMENT link (#PCDATA)>
<!ATTLIST link
rel (main|search|signIn|signOut|signUp|refillAccount|recoverPassword) #REQUIRED
type CDATA #REQUIRED
>
<!ELEMENT relationAliases (alias+)>
<!ELEMENT alias EMPTY>
<!ATTLIST alias
alias CDATA #REQUIRED
name CDATA #REQUIRED
type CDATA ""
>
<!ELEMENT advancedSearch (field+)>
<!ATTLIST advancedSearch
style (separateWords|quoted) #REQUIRED
>
<!ELEMENT field (#PCDATA)>
<!ATTLIST field
name (author|titleOrSeries|tag|annotation) #REQUIRED
>
<!ELEMENT feeds (condition+)>
<!ELEMENT condition (#PCDATA)>
<!ATTLIST condition
show (never|signedIn) #REQUIRED
>
<!ELEMENT authentication EMPTY>
<!ATTLIST authentication
type (basic|litres) #REQUIRED
>
<!ELEMENT urlRewritingRules (rule+)>
<!ELEMENT rule EMPTY>
<!ATTLIST rule
type (addUrlParameter) #REQUIRED
apply (always|external|internal) "always"
name CDATA #REQUIRED
value CDATA #REQUIRED
>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE catalog SYSTEM "catalog.dtd"> <!DOCTYPE catalog SYSTEM "catalog.dtd">
<catalog type="opds"> <catalog type="opds" hasStableIdentifiers="true">
<site>feedbooks.com</site> <site>feedbooks.com</site>
<title>Feedbooks OPDS Catalog</title> <title>Feedbooks OPDS Catalog</title>
<summary>Feedbooks: Food for the mind. A place to discover and publish e-books.</summary> <summary>Feedbooks: Food for the mind. A place to discover and publish e-books.</summary>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE catalog SYSTEM "catalog.dtd"> <!DOCTYPE catalog SYSTEM "catalog.dtd">
<catalog type="opds"> <catalog type="opds" hasStableIdentifiers="true">
<site>litres.ru</site> <site>litres.ru</site>
<title>Каталог LitRes</title> <title>Каталог LitRes</title>
<summary>Продажа электронных книг.</summary> <summary>Продажа электронных книг.</summary>

View file

@ -21,6 +21,7 @@ package org.geometerplus.android.fbreader.network;
import org.geometerplus.zlibrary.core.resources.ZLResource; import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.fbreader.network.NetworkLibraryItem;
import org.geometerplus.fbreader.network.NetworkTree; import org.geometerplus.fbreader.network.NetworkTree;
@ -39,4 +40,9 @@ public class AddCustomCatalogItemTree extends NetworkTree {
public String getSummary() { public String getSummary() {
return null; return null;
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
} }

View file

@ -19,12 +19,16 @@
package org.geometerplus.android.fbreader.network; package org.geometerplus.android.fbreader.network;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import android.os.Message; import android.os.Message;
import android.os.Handler; import android.os.Handler;
import org.geometerplus.fbreader.network.INetworkLink;
import org.geometerplus.fbreader.network.NetworkLibraryItem; import org.geometerplus.fbreader.network.NetworkLibraryItem;
@ -34,15 +38,31 @@ abstract class ItemsLoadingHandler extends Handler {
private static final int WHAT_FINISHED = 1; private static final int WHAT_FINISHED = 1;
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>(); private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
private final HashMap<INetworkLink, LinkedList<NetworkLibraryItem>> myUncommitedItems = new HashMap<INetworkLink, LinkedList<NetworkLibraryItem>>();
private final Object myItemsMonitor = new Object(); private final Object myItemsMonitor = new Object();
private volatile boolean myFinishProcessed; private volatile boolean myFinishProcessed;
private final Object myFinishMonitor = new Object(); private final Object myFinishMonitor = new Object();
public final void addItem(NetworkLibraryItem item) { public final void addItem(INetworkLink link, NetworkLibraryItem item) {
synchronized (myItemsMonitor) { synchronized (myItemsMonitor) {
myItems.add(item); myItems.add(item);
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
if (uncommited == null) {
uncommited = new LinkedList<NetworkLibraryItem>();
myUncommitedItems.put(link, uncommited);
}
uncommited.add(item);
}
}
public final void commitItems(INetworkLink link) {
synchronized (myItemsMonitor) {
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
if (uncommited != null) {
uncommited.clear();
}
} }
} }
@ -78,8 +98,14 @@ abstract class ItemsLoadingHandler extends Handler {
} }
private final void doProcessFinish(String errorMessage, boolean interrupted) { private final void doProcessFinish(String errorMessage, boolean interrupted) {
HashSet<NetworkLibraryItem> uncommitedItems = new HashSet<NetworkLibraryItem>();
synchronized (myUncommitedItems) {
for (LinkedList<NetworkLibraryItem> items: myUncommitedItems.values()) {
uncommitedItems.addAll(items);
}
}
synchronized (myFinishMonitor) { synchronized (myFinishMonitor) {
onFinish(errorMessage, interrupted); onFinish(errorMessage, interrupted, uncommitedItems);
myFinishProcessed = true; myFinishProcessed = true;
myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method) myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
} }
@ -100,7 +126,7 @@ abstract class ItemsLoadingHandler extends Handler {
// callbacks // callbacks
public abstract void onUpdateItems(List<NetworkLibraryItem> items); public abstract void onUpdateItems(List<NetworkLibraryItem> items);
public abstract void afterUpdateItems(); public abstract void afterUpdateItems();
public abstract void onFinish(String errorMessage, boolean interrupted); public abstract void onFinish(String errorMessage, boolean interrupted, Set<NetworkLibraryItem> uncommitedItems);
@Override @Override

View file

@ -22,6 +22,7 @@ package org.geometerplus.android.fbreader.network;
import android.os.Message; import android.os.Message;
import android.os.Handler; import android.os.Handler;
import org.geometerplus.fbreader.network.INetworkLink;
import org.geometerplus.fbreader.network.NetworkOperationData; import org.geometerplus.fbreader.network.NetworkOperationData;
import org.geometerplus.fbreader.network.NetworkLibraryItem; import org.geometerplus.fbreader.network.NetworkLibraryItem;
@ -98,8 +99,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
err = doLoading(new NetworkOperationData.OnNewItemListener() { err = doLoading(new NetworkOperationData.OnNewItemListener() {
private long myUpdateTime; private long myUpdateTime;
private int myItemsNumber; private int myItemsNumber;
public void onNewItem(NetworkLibraryItem item) { public void onNewItem(INetworkLink link, NetworkLibraryItem item) {
myHandler.addItem(item); myHandler.addItem(link, item);
++myItemsNumber; ++myItemsNumber;
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
if (now > myUpdateTime) { if (now > myUpdateTime) {
@ -110,6 +111,9 @@ abstract class ItemsLoadingRunnable implements Runnable {
public boolean confirmInterrupt() { public boolean confirmInterrupt() {
return confirmInterruptLoading() || myItemsNumber >= ItemsLimit; return confirmInterruptLoading() || myItemsNumber >= ItemsLimit;
} }
public void commitItems(INetworkLink link) {
myHandler.commitItems(link);
}
}); });
myHandler.sendUpdateItems(); myHandler.sendUpdateItems();
myHandler.ensureItemsProcessed(); myHandler.ensureItemsProcessed();

View file

@ -20,6 +20,7 @@
package org.geometerplus.android.fbreader.network; package org.geometerplus.android.fbreader.network;
import java.util.List; import java.util.List;
import java.util.Set;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.os.Message; import android.os.Message;
@ -274,6 +275,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
myKey = key; myKey = key;
} }
@Override
public void onUpdateItems(List<NetworkLibraryItem> items) { public void onUpdateItems(List<NetworkLibraryItem> items) {
for (NetworkLibraryItem item: items) { for (NetworkLibraryItem item: items) {
myTree.ChildrenItems.add(item); myTree.ChildrenItems.add(item);
@ -281,20 +283,26 @@ class NetworkCatalogActions extends NetworkTreeActions {
} }
} }
@Override
public void afterUpdateItems() { public void afterUpdateItems() {
if (NetworkView.Instance().isInitialized()) { if (NetworkView.Instance().isInitialized()) {
NetworkView.Instance().fireModelChanged(); NetworkView.Instance().fireModelChanged();
} }
} }
public void onFinish(String errorMessage, boolean interrupted) { @Override
public void onFinish(String errorMessage, boolean interrupted,
Set<NetworkLibraryItem> uncommitedItems) {
if (interrupted && if (interrupted &&
(!myTree.Item.supportsResumeLoading() || errorMessage != null)) { (!myTree.Item.supportsResumeLoading() || errorMessage != null)) {
myTree.ChildrenItems.clear(); myTree.ChildrenItems.clear();
myTree.clear(); myTree.clear();
} else { } else {
myTree.removeItems(uncommitedItems);
myTree.updateLoadedTime(); myTree.updateLoadedTime();
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0); if (!interrupted) {
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
}
final NetworkLibrary library = NetworkLibrary.Instance(); final NetworkLibrary library = NetworkLibrary.Instance();
library.invalidateVisibility(); library.invalidateVisibility();
library.synchronize(); library.synchronize();

View file

@ -20,6 +20,7 @@
package org.geometerplus.android.fbreader.network; package org.geometerplus.android.fbreader.network;
import java.util.List; import java.util.List;
import java.util.Set;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Activity; import android.app.Activity;
@ -62,6 +63,7 @@ public class NetworkSearchActivity extends Activity {
myTree = tree; myTree = tree;
} }
@Override
public void onUpdateItems(List<NetworkLibraryItem> items) { public void onUpdateItems(List<NetworkLibraryItem> items) {
SearchResult result = myTree.getSearchResult(); SearchResult result = myTree.getSearchResult();
for (NetworkLibraryItem item: items) { for (NetworkLibraryItem item: items) {
@ -71,6 +73,7 @@ public class NetworkSearchActivity extends Activity {
} }
} }
@Override
public void afterUpdateItems() { public void afterUpdateItems() {
myTree.updateSubTrees(); myTree.updateSubTrees();
if (NetworkView.Instance().isInitialized()) { if (NetworkView.Instance().isInitialized()) {
@ -78,7 +81,9 @@ public class NetworkSearchActivity extends Activity {
} }
} }
public void onFinish(String errorMessage, boolean interrupted) { @Override
public void onFinish(String errorMessage, boolean interrupted,
Set<NetworkLibraryItem> uncommitedItems) {
if (interrupted) { if (interrupted) {
myTree.setSearchResult(null); myTree.setSearchResult(null);
} else { } else {

View file

@ -24,6 +24,7 @@ import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.zlibrary.core.util.ZLBoolean3; import org.geometerplus.zlibrary.core.util.ZLBoolean3;
import org.geometerplus.fbreader.network.INetworkLink; import org.geometerplus.fbreader.network.INetworkLink;
import org.geometerplus.fbreader.network.NetworkLibraryItem;
import org.geometerplus.fbreader.network.NetworkTree; import org.geometerplus.fbreader.network.NetworkTree;
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree; import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager; import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
@ -61,4 +62,9 @@ class RefillAccountTree extends NetworkTree {
protected ZLImage createCover() { protected ZLImage createCover() {
return Cover; return Cover;
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
} }

View file

@ -99,4 +99,9 @@ public class SearchItemTree extends NetworkTree {
throw new RuntimeException("That's impossible!!!"); throw new RuntimeException("That's impossible!!!");
} }
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
} }

View file

@ -411,12 +411,15 @@ public class NetworkLibrary {
LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>(); LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>();
final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() { final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
public synchronized void onNewItem(NetworkLibraryItem item) { public synchronized void onNewItem(INetworkLink link, NetworkLibraryItem item) {
listener.onNewItem(item); listener.onNewItem(link, item);
} }
public synchronized boolean confirmInterrupt() { public synchronized boolean confirmInterrupt() {
return listener.confirmInterrupt(); return listener.confirmInterrupt();
} }
public synchronized void commitItems(INetworkLink link) {
listener.commitItems(link);
}
}; };
synchronized (myLinks) { synchronized (myLinks) {

View file

@ -25,9 +25,12 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
public class NetworkOperationData { public class NetworkOperationData {
public interface OnNewItemListener { public interface OnNewItemListener {
void onNewItem(NetworkLibraryItem item); void onNewItem(INetworkLink link, NetworkLibraryItem item);
// return true to confirm interrupt reading; return false to continue reading void commitItems(INetworkLink link);
// returns true to confirm interrupt reading; return false to continue reading.
// once true has been returned, all next calls must return true.
boolean confirmInterrupt(); boolean confirmInterrupt();
} }

View file

@ -19,6 +19,9 @@
package org.geometerplus.fbreader.network; package org.geometerplus.fbreader.network;
import java.util.LinkedList;
import java.util.Set;
import org.geometerplus.fbreader.tree.FBTree; import org.geometerplus.fbreader.tree.FBTree;
import org.geometerplus.zlibrary.core.image.ZLImage; import org.geometerplus.zlibrary.core.image.ZLImage;
@ -80,4 +83,33 @@ public abstract class NetworkTree extends FBTree {
} }
return null; return null;
} }
public abstract NetworkLibraryItem getHoldedItem();
public void removeItems(Set<NetworkLibraryItem> items) {
if (items.isEmpty() || subTrees().isEmpty()) {
return;
}
final LinkedList<FBTree> treesList = new LinkedList<FBTree>();
for (FBTree tree: subTrees()) {
final NetworkLibraryItem treeItem = ((NetworkTree)tree).getHoldedItem();
if (treeItem != null && items.contains(treeItem)) {
treesList.add(tree);
items.remove(treeItem);
}
}
for (FBTree tree: treesList) {
tree.removeSelf();
}
if (items.isEmpty()) {
return;
}
treesList.clear();
treesList.addAll(subTrees());
while (!treesList.isEmpty()) {
final NetworkTree tree = (NetworkTree) treesList.remove(treesList.size() - 1);
tree.removeItems(items);
}
}
} }

View file

@ -64,8 +64,9 @@ public class LitResBookshelfItem extends NetworkCatalogItem {
mgr.collectPurchasedBooks(children); mgr.collectPurchasedBooks(children);
Collections.sort(children, new NetworkBookItemComparator()); Collections.sort(children, new NetworkBookItemComparator());
for (NetworkLibraryItem item: children) { for (NetworkLibraryItem item: children) {
listener.onNewItem(item); listener.onNewItem(Link, item);
} }
listener.commitItems(Link);
return error; return error;
} }
} }

View file

@ -36,7 +36,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
private int myIndex; private int myIndex;
private String myNextURL; private String myNextURL;
private String mySkipUntilTitle; private String mySkipUntilId;
private int myItemsToLoad = -1; private int myItemsToLoad = -1;
@ -50,7 +50,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
NetworkOPDSFeedReader(String baseURL, OPDSCatalogItem.State result) { NetworkOPDSFeedReader(String baseURL, OPDSCatalogItem.State result) {
myBaseURL = baseURL; myBaseURL = baseURL;
myData = result; myData = result;
mySkipUntilTitle = myData.LastLoadedTitle; mySkipUntilId = myData.LastLoadedId;
if (!(result.Link instanceof OPDSLink)) { if (!(result.Link instanceof OPDSLink)) {
throw new IllegalArgumentException("Parameter `result` has invalid `Link` field value: result.Link must be an instance of OPDSLink class."); throw new IllegalArgumentException("Parameter `result` has invalid `Link` field value: result.Link must be an instance of OPDSLink class.");
} }
@ -91,14 +91,14 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
} }
public void processFeedEnd() { public void processFeedEnd() {
if (mySkipUntilTitle != null) { if (mySkipUntilId != null) {
// Last loaded element was not found => resume error => DO NOT RESUME // Last loaded element was not found => resume error => DO NOT RESUME
// TODO: notify user about error??? // TODO: notify user about error???
// TODO: do reload??? // TODO: do reload???
myNextURL = null; myNextURL = null;
} }
myData.ResumeURI = myNextURL; myData.ResumeURI = myNextURL;
myData.LastLoadedTitle = null; myData.LastLoadedId = null;
} }
@ -142,13 +142,13 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
--myItemsToLoad; --myItemsToLoad;
} }
if (mySkipUntilTitle != null) { if (mySkipUntilId != null) {
if (mySkipUntilTitle.equals(entry.Title)) { if (mySkipUntilId.equals(entry.Id.Uri)) {
mySkipUntilTitle = null; mySkipUntilId = null;
} }
return tryInterrupt(); return tryInterrupt();
} }
myData.LastLoadedTitle = entry.Title; myData.LastLoadedId = entry.Id.Uri;
final OPDSLink opdsLink = (OPDSLink) myData.Link; final OPDSLink opdsLink = (OPDSLink) myData.Link;
if (opdsLink.getCondition(entry.Id.Uri) == OPDSLink.FeedCondition.NEVER) { if (opdsLink.getCondition(entry.Id.Uri) == OPDSLink.FeedCondition.NEVER) {
@ -176,7 +176,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader {
item = readCatalogItem(entry); item = readCatalogItem(entry);
} }
if (item != null) { if (item != null) {
myData.Listener.onNewItem(item); myData.Listener.onNewItem(myData.Link, item);
} }
return tryInterrupt(); return tryInterrupt();
} }

View file

@ -31,7 +31,7 @@ class OPDSCatalogItem extends NetworkCatalogItem {
static class State extends NetworkOperationData { static class State extends NetworkOperationData {
public String LastLoadedTitle; public String LastLoadedId;
public State(INetworkLink link, OnNewItemListener listener) { public State(INetworkLink link, OnNewItemListener listener) {
super(link, listener); super(link, listener);

View file

@ -30,7 +30,7 @@ class OPDSCustomLink extends OPDSLink implements ICustomNetworkLink {
private SaveLinkListener myListener; private SaveLinkListener myListener;
OPDSCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) { OPDSCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) {
super(siteName, title, summary, icon, links); super(siteName, title, summary, icon, links, false);
myId = id; myId = id;
} }

View file

@ -45,8 +45,12 @@ class OPDSLink extends AbstractNetworkLink {
private LinkedList<URLRewritingRule> myUrlRewritingRules; private LinkedList<URLRewritingRule> myUrlRewritingRules;
private NetworkAuthenticationManager myAuthenticationManager; private NetworkAuthenticationManager myAuthenticationManager;
OPDSLink(String siteName, String title, String summary, String icon, Map<String, String> links) { private final boolean myHasStableIdentifiers;
OPDSLink(String siteName, String title, String summary, String icon,
Map<String, String> links, boolean hasStableIdentifiers) {
super(siteName, title, summary, icon, links); super(siteName, title, summary, icon, links);
myHasStableIdentifiers = hasStableIdentifiers;
} }
final void setRelationAliases(Map<RelationAlias, String> relationAliases) { final void setRelationAliases(Map<RelationAlias, String> relationAliases) {
@ -88,9 +92,23 @@ class OPDSLink extends AbstractNetworkLink {
if (result.Listener.confirmInterrupt()) { if (result.Listener.confirmInterrupt()) {
return null; return null;
} }
new OPDSXMLReader( new OPDSXMLReader(
new NetworkOPDSFeedReader(URL, result) new NetworkOPDSFeedReader(URL, result)
).read(inputStream); ).read(inputStream);
if (result.Listener.confirmInterrupt()) {
if (!myHasStableIdentifiers && result.LastLoadedId != null) {
// If current catalog doesn't have stable identifiers
// and catalog wasn't completely loaded (i.e. LastLoadedIdentifier is not null)
// then reset state to load current page from the beginning
result.LastLoadedId = null;
} else {
result.Listener.commitItems(OPDSLink.this);
}
} else {
result.Listener.commitItems(OPDSLink.this);
}
return null; return null;
} }
}; };

View file

@ -36,6 +36,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
private String myTitle; private String myTitle;
private String mySummary; private String mySummary;
private String myIcon; private String myIcon;
private boolean myHasStableIdentifiers;
private final HashMap<String, String> myLinks = new HashMap<String, String>(); private final HashMap<String, String> myLinks = new HashMap<String, String>();
@ -60,7 +61,8 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
myTitle, myTitle,
mySummary, mySummary,
myIcon, myIcon,
myLinks myLinks,
myHasStableIdentifiers
); );
/*if (!mySearchType.empty()) { /*if (!mySearchType.empty()) {
@ -102,6 +104,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
public INetworkLink readDocument(ZLFile file) { public INetworkLink readDocument(ZLFile file) {
mySiteName = myTitle = mySummary = myIcon = /*mySearchType = */myAuthenticationType = mySSLCertificate = null; mySiteName = myTitle = mySummary = myIcon = /*mySearchType = */myAuthenticationType = mySSLCertificate = null;
myHasStableIdentifiers = false;
myLinks.clear(); myLinks.clear();
mySearchFields.clear(); mySearchFields.clear();
myUrlConditions.clear(); myUrlConditions.clear();
@ -126,6 +129,7 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
} }
private static final String TAG_CATALOG = "catalog";
private static final String TAG_SITE = "site"; private static final String TAG_SITE = "site";
private static final String TAG_LINK = "link"; private static final String TAG_LINK = "link";
private static final String TAG_TITLE = "title"; private static final String TAG_TITLE = "title";
@ -163,7 +167,10 @@ public class OPDSLinkReader extends ZLXMLReaderAdapter {
@Override @Override
public boolean startElementHandler(String tag, ZLStringMap attributes) { public boolean startElementHandler(String tag, ZLStringMap attributes) {
tag = tag.intern(); tag = tag.intern();
if (TAG_SITE == tag) { if (TAG_CATALOG == tag) {
final String value = attributes.getValue("hasStableIdentifiers");
myHasStableIdentifiers = value != null && value.equals("true");
} else if (TAG_SITE == tag) {
myState = READ_SITENAME; myState = READ_SITENAME;
} else if (TAG_TITLE == tag) { } else if (TAG_TITLE == tag) {
myState = READ_TITLE; myState = READ_TITLE;

View file

@ -118,4 +118,9 @@ public class NetworkAuthorTree extends NetworkTree {
myBooksNumber = books.size(); myBooksNumber = books.size();
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
} }

View file

@ -67,4 +67,9 @@ public class NetworkBookTree extends NetworkTree {
protected ZLImage createCover() { protected ZLImage createCover() {
return createCover(Book); return createCover(Book);
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return Book;
}
} }

View file

@ -156,4 +156,15 @@ public class NetworkCatalogTree extends NetworkTree {
tree.removeSelf(); tree.removeSelf();
} }
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return Item;
}
@Override
public void removeItems(Set<NetworkLibraryItem> items) {
ChildrenItems.removeAll(items);
super.removeItems(items);
}
} }

View file

@ -85,4 +85,17 @@ public class NetworkSeriesTree extends NetworkTree {
} }
return null; return null;
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
@Override
public void removeItems(Set<NetworkLibraryItem> items) {
super.removeItems(items);
if (subTrees().isEmpty()) {
removeSelf();
}
}
} }

View file

@ -19,6 +19,7 @@
package org.geometerplus.fbreader.network.tree; package org.geometerplus.fbreader.network.tree;
import org.geometerplus.fbreader.network.NetworkLibraryItem;
import org.geometerplus.fbreader.network.NetworkTree; import org.geometerplus.fbreader.network.NetworkTree;
public final class RootTree extends NetworkTree { public final class RootTree extends NetworkTree {
@ -26,4 +27,9 @@ public final class RootTree extends NetworkTree {
public String getName() { public String getName() {
return null; return null;
} }
@Override
public NetworkLibraryItem getHoldedItem() {
return null;
}
} }