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

added context menu for TOC

selected current item in TOC
implemented tag tree in library
implemented full library database


git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@909 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
Nikolay Pultsin 2009-04-06 15:57:40 +00:00
parent fad63e3659
commit 68167fe2bc
43 changed files with 1055 additions and 1237 deletions

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<org.geometerplus.android.fbreader.TOCTreeItemView xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
@ -39,4 +39,4 @@
android:textAppearance="?android:attr/textAppearanceSmall"
/>
</LinearLayout>
</org.geometerplus.android.fbreader.TOCTreeItemView>
</LinearLayout>

View file

@ -26,6 +26,8 @@ import org.geometerplus.zlibrary.ui.android.library.ZLAndroidActivity;
public class FBReader extends ZLAndroidActivity {
protected ZLApplication createApplication(String fileName) {
String[] args = (fileName != null) ? new String[] { fileName } : new String[0];
return new org.geometerplus.fbreader.fbreader.FBReader(args);
ZLApplication application = new org.geometerplus.fbreader.fbreader.FBReader(args);
new SQLiteBooksDatabase();
return application;
}
}

View file

@ -0,0 +1,368 @@
/*
* Copyright (C) 2009 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.android.fbreader;
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.database.SQLException;
import android.database.Cursor;
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication;
import org.geometerplus.fbreader.collection.*;
final class SQLiteBooksDatabase extends BooksDatabase {
private final SQLiteDatabase myDatabase;
SQLiteBooksDatabase() {
myDatabase = ZLAndroidApplication.Instance().openOrCreateDatabase("books.db", Context.MODE_PRIVATE, null);
if (myDatabase.getVersion() == 0) {
createTables();
}
}
public void executeAsATransaction(Runnable actions) {
myDatabase.beginTransaction();
try {
actions.run();
myDatabase.setTransactionSuccessful();
} finally {
myDatabase.endTransaction();
}
}
private void createTables() {
myDatabase.beginTransaction();
/*
myDatabase.execSQL("DROP TABLE Books");
myDatabase.execSQL("DROP TABLE Authors");
myDatabase.execSQL("DROP TABLE Series");
myDatabase.execSQL("DROP TABLE Tags");
myDatabase.execSQL("DROP TABLE BookAuthor");
myDatabase.execSQL("DROP TABLE BookSeries");
myDatabase.execSQL("DROP TABLE BookTag");
*/
myDatabase.execSQL(
"CREATE TABLE Books(" +
"book_id INTEGER PRIMARY KEY," +
"encoding TEXT," +
"language TEXT," +
"title TEXT NOT NULL," +
"file_name TEXT UNIQUE NOT NULL)");
myDatabase.execSQL(
"CREATE TABLE Authors(" +
"author_id INTEGER PRIMARY KEY," +
"name TEXT NOT NULL," +
"sort_key TEXT NOT NULL," +
"CONSTRAINT Authors_Unique UNIQUE (name, sort_key))");
myDatabase.execSQL(
"CREATE TABLE BookAuthor(" +
"author_id INTEGER NOT NULL REFERENCES Authors(author_id)," +
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
"author_index INTEGER NOT NULL," +
"CONSTRAINT BookAuthor_Unique0 UNIQUE (author_id, book_id)," +
"CONSTRAINT BookAuthor_Unique1 UNIQUE (book_id, author_index))");
myDatabase.execSQL(
"CREATE TABLE Series(" +
"series_id INTEGER PRIMARY KEY," +
"name TEXT UNIQUE NOT NULL)");
myDatabase.execSQL(
"CREATE TABLE BookSeries(" +
"series_id INTEGER NOT NULL REFERENCES Series(series_id)," +
"book_id INTEGER NOT NULL UNIQUE REFERENCES Books(book_id)," +
"book_index INTEGER)");
myDatabase.execSQL(
"CREATE TABLE Tags(" +
"tag_id INTEGER PRIMARY KEY," +
"name TEXT NOT NULL," +
"parent INTEGER REFERENCES Tags(tag_id)," +
"CONSTRAINT Tags_Unique UNIQUE (name, parent))");
myDatabase.execSQL(
"CREATE TABLE BookTag(" +
"tag_id INTEGER REFERENCES Tags(tag_id)," +
"book_id INTEGER REFERENCES Books(book_id)," +
"CONSTRAINT BookTag_Unique UNIQUE (tag_id, book_id))");
myDatabase.setTransactionSuccessful();
myDatabase.endTransaction();
myDatabase.setVersion(1);
}
private static void bindString(SQLiteStatement statement, int index, String value) {
if (value != null) {
statement.bindString(index, value);
} else {
statement.bindNull(index);
}
}
private static final String BOOKS_TABLE = "Books";
private static final String[] BOOKS_COLUMNS = { "book_id", "encoding", "language", "title" };
private static final String FILE_NAME_CONDITION = "file_name = ?";
public long loadBook(BookDescription description) {
final Cursor cursor = myDatabase.query(
BOOKS_TABLE,
BOOKS_COLUMNS,
FILE_NAME_CONDITION, new String[] { description.FileName },
null, null, null, null
);
long id = -1;
if (cursor.moveToNext()) {
id = cursor.getLong(0);
description.setEncoding(cursor.getString(1));
description.setLanguage(cursor.getString(2));
description.setTitle(cursor.getString(3));
}
cursor.close();
return id;
}
private SQLiteStatement myUpdateBookInfoStatement;
public void updateBookInfo(long bookId, String encoding, String language, String title) {
if (myUpdateBookInfoStatement == null) {
myUpdateBookInfoStatement = myDatabase.compileStatement(
"UPDATE Books SET encoding = ? language = ? title = ? WHERE book_id = ?"
);
}
bindString(myUpdateBookInfoStatement, 1, encoding);
bindString(myUpdateBookInfoStatement, 2, language);
myUpdateBookInfoStatement.bindString(3, title);
myUpdateBookInfoStatement.bindLong(4, bookId);
myUpdateBookInfoStatement.execute();
}
private SQLiteStatement myInsertBookInfoStatement;
public long insertBookInfo(String fileName, String encoding, String language, String title) {
if (myInsertBookInfoStatement == null) {
myInsertBookInfoStatement = myDatabase.compileStatement(
"INSERT INTO Books (encoding,language,title,file_name) VALUES (?,?,?,?)"
);
}
bindString(myInsertBookInfoStatement, 1, encoding);
bindString(myInsertBookInfoStatement, 2, language);
myInsertBookInfoStatement.bindString(3, title);
myInsertBookInfoStatement.bindString(4, fileName);
return myInsertBookInfoStatement.executeInsert();
}
private SQLiteStatement myGetAuthorIdStatement;
private SQLiteStatement myInsertAuthorStatement;
private SQLiteStatement myInsertBookAuthorStatement;
public void saveBookAuthorInfo(long bookId, long index, Author author) {
if (myGetAuthorIdStatement == null) {
myGetAuthorIdStatement = myDatabase.compileStatement(
"SELECT author_id FROM Authors WHERE name = ? AND sort_key = ?"
);
myInsertAuthorStatement = myDatabase.compileStatement(
"INSERT INTO Authors (name,sort_key) VALUES (?,?)"
);
myInsertBookAuthorStatement = myDatabase.compileStatement(
"INSERT OR IGNORE INTO BookAuthor (book_id,author_id,author_index) VALUES (?,?,?)"
);
}
long authorId;
try {
myGetAuthorIdStatement.bindString(1, author.DisplayName);
myGetAuthorIdStatement.bindString(2, author.SortKey);
authorId = myGetAuthorIdStatement.simpleQueryForLong();
} catch (SQLException e) {
myInsertAuthorStatement.bindString(1, author.DisplayName);
myInsertAuthorStatement.bindString(2, author.SortKey);
authorId = myInsertAuthorStatement.executeInsert();
}
myInsertBookAuthorStatement.bindLong(1, bookId);
myInsertBookAuthorStatement.bindLong(2, authorId);
myInsertBookAuthorStatement.bindLong(3, index);
myInsertBookAuthorStatement.execute();
}
public ArrayList<Author> loadAuthors(long bookId) {
final Cursor cursor = myDatabase.rawQuery("SELECT Authors.name,Authors.sort_key FROM BookAuthor INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id WHERE BookAuthor.book_id = ?", new String[] { "" + bookId });
if (!cursor.moveToNext()) {
return null;
}
ArrayList<Author> list = new ArrayList<Author>(cursor.getCount());
do {
list.add(new Author(cursor.getString(0), cursor.getString(1)));
} while (cursor.moveToNext());
cursor.close();
return list;
}
private HashMap<Tag,Long> myIdByTag = new HashMap<Tag,Long>();
private HashMap<Long,Tag> myTagById = new HashMap<Long,Tag>();
private SQLiteStatement myGetTagIdStatement;
private SQLiteStatement myCreateTagIdStatement;
private long getTagId(Tag tag) {
if (myGetTagIdStatement == null) {
myGetTagIdStatement = myDatabase.compileStatement(
"SELECT tag_id FROM Tags WHERE parent = ? AND name = ?"
);
myCreateTagIdStatement = myDatabase.compileStatement(
"INSERT INTO Tags (parent,name) VALUES (?,?)"
);
}
{
final Long id = myIdByTag.get(tag);
if (id != null) {
return id;
}
}
if (tag.Parent != null) {
myGetTagIdStatement.bindLong(1, getTagId(tag.Parent));
} else {
myGetTagIdStatement.bindNull(1);
}
myGetTagIdStatement.bindString(2, tag.Name);
long id;
try {
id = myGetTagIdStatement.simpleQueryForLong();
} catch (SQLException e) {
if (tag.Parent != null) {
myCreateTagIdStatement.bindLong(1, getTagId(tag.Parent));
} else {
myCreateTagIdStatement.bindNull(1);
}
myCreateTagIdStatement.bindString(2, tag.Name);
id = myCreateTagIdStatement.executeInsert();
}
myIdByTag.put(tag, id);
myTagById.put(id, tag);
return id;
}
private SQLiteStatement myInsertBookTagStatement;
public void saveBookTagInfo(long bookId, Tag tag) {
if (myInsertBookTagStatement == null) {
myInsertBookTagStatement = myDatabase.compileStatement(
"INSERT INTO BookTag (book_id,tag_id) VALUES (?,?)"
);
}
myInsertBookTagStatement.bindLong(1, bookId);
myInsertBookTagStatement.bindLong(2, getTagId(tag));
myInsertBookTagStatement.execute();
}
private Tag getTagById(long id) {
Tag tag = myTagById.get(id);
if (tag == null) {
final Cursor cursor = myDatabase.rawQuery("SELECT parent,name FROM Tags WHERE tag_id = ?", new String[] { "" + id });
if (cursor.moveToNext()) {
final Tag parent = cursor.isNull(0) ? null : getTagById(cursor.getLong(0));
tag = Tag.getTag(parent, cursor.getString(1));
myIdByTag.put(tag, id);
myTagById.put(id, tag);
}
cursor.close();
}
return tag;
}
public ArrayList<Tag> loadTags(long bookId) {
final Cursor cursor = myDatabase.rawQuery("SELECT Tags.tag_id FROM BookTag INNER JOIN Tags ON Tags.tag_id = BookTag.tag_id WHERE BookTag.book_id = ?", new String[] { "" + bookId });
if (!cursor.moveToNext()) {
return null;
}
ArrayList<Tag> list = new ArrayList<Tag>(cursor.getCount());
do {
list.add(getTagById(cursor.getLong(0)));
} while (cursor.moveToNext());
cursor.close();
return list;
}
private SQLiteStatement myGetSeriesIdStatement;
private SQLiteStatement myInsertSeriesStatement;
private SQLiteStatement myInsertBookSeriesStatement;
private SQLiteStatement myDeleteBookSeriesStatement;
public void saveBookSeriesInfo(long bookId, SeriesInfo seriesInfo) {
if (myGetSeriesIdStatement == null) {
myGetSeriesIdStatement = myDatabase.compileStatement(
"SELECT series_id FROM Series WHERE name = ?"
);
myInsertSeriesStatement = myDatabase.compileStatement(
"INSERT INTO Series (name) VALUES (?)"
);
myInsertBookSeriesStatement = myDatabase.compileStatement(
"INSERT OR REPLACE INTO BookSeries (book_id,series_id,book_index) VALUES (?,?,?)"
);
myDeleteBookSeriesStatement = myDatabase.compileStatement(
"DELETE FROM BookSeries WHERE book_id = ?"
);
}
if (seriesInfo == null) {
myDeleteBookSeriesStatement.bindLong(1, bookId);
myDeleteBookSeriesStatement.execute();
} else {
long seriesId;
try {
myGetSeriesIdStatement.bindString(1, seriesInfo.Name);
seriesId = myGetSeriesIdStatement.simpleQueryForLong();
} catch (SQLException e) {
myInsertSeriesStatement.bindString(1, seriesInfo.Name);
seriesId = myInsertSeriesStatement.executeInsert();
}
myInsertBookSeriesStatement.bindLong(1, bookId);
myInsertBookSeriesStatement.bindLong(2, seriesId);
myInsertBookSeriesStatement.bindLong(3, seriesInfo.Index);
myInsertBookSeriesStatement.execute();
}
}
public SeriesInfo loadSeriesInfo(long bookId) {
final Cursor cursor = myDatabase.rawQuery("SELECT Series.name,BookSeries.book_index FROM BookSeries INNER JOIN Series ON Series.series_id = BookSeries.series_id WHERE BookSeries.book_id = ?", new String[] { "" + bookId });
SeriesInfo info = null;
if (cursor.moveToNext()) {
info = new SeriesInfo(cursor.getString(0), cursor.getLong(1));
}
cursor.close();
return info;
}
private SQLiteStatement myResetBookInfoStatement;
private final static String myBookIdWhereClause = "book_id = ?";
public void resetBookInfo(String fileName) {
if (myResetBookInfoStatement == null) {
myResetBookInfoStatement = myDatabase.compileStatement(
"SELECT book_id FROM Books WHERE file_name = ?"
);
}
myResetBookInfoStatement.bindString(1, fileName);
try {
final long bookId = myResetBookInfoStatement.simpleQueryForLong();
final String[] parameters = { "" + bookId };
executeAsATransaction(new Runnable() {
public void run() {
myDatabase.delete("Books", myBookIdWhereClause, parameters);
myDatabase.delete("BookAuthor", myBookIdWhereClause, parameters);
myDatabase.delete("BookSeries", myBookIdWhereClause, parameters);
myDatabase.delete("BookTag", myBookIdWhereClause, parameters);
}
});
} catch (SQLException e) {
}
}
}

View file

@ -21,8 +21,7 @@ package org.geometerplus.android.fbreader;
import android.os.Bundle;
import android.view.*;
import android.widget.TextView;
import android.widget.ImageView;
import android.widget.*;
import android.content.Context;
import android.app.ListActivity;
import android.content.res.TypedArray;
@ -30,22 +29,46 @@ import android.graphics.drawable.Drawable;
import org.geometerplus.zlibrary.core.application.ZLApplication;
import org.geometerplus.zlibrary.core.tree.ZLTree;
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
import org.geometerplus.zlibrary.ui.android.R;
import org.geometerplus.fbreader.bookmodel.ContentsTree;
import org.geometerplus.zlibrary.text.view.impl.ZLTextWordCursor;
import org.geometerplus.fbreader.bookmodel.TOCTree;
import org.geometerplus.fbreader.fbreader.FBReader;
import org.geometerplus.fbreader.fbreader.BookTextView;
public class TOCActivity extends ListActivity {
private TOCAdapter myAdapter;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
final FBReader fbreader = (FBReader)ZLApplication.Instance();
new TOCAdapter(fbreader.Model.ContentsTree);
final TOCTree root = fbreader.Model.TOCTree;
myAdapter = new TOCAdapter(root);
final ZLTextWordCursor cursor = fbreader.BookTextView.StartCursor;
int index = cursor.getParagraphCursor().Index;
if (cursor.isEndOfParagraph()) {
++index;
}
TOCTree treeToSelect = null;
// TODO: rewrite for better speed
// TODO: process multi-model texts
for (int i = 0; i < root.getSize(); ++i) {
final TOCTree tree = root.getTree(i);
final TOCTree.Reference reference = tree.getReference();
if (reference == null) {
continue;
}
if (reference.ParagraphIndex > index) {
break;
}
treeToSelect = tree;
}
myAdapter.selectItem(treeToSelect);
/*
int selectedIndex = adapter.getSelectedIndex();
if (selectedIndex >= 0) {
@ -54,31 +77,69 @@ public class TOCActivity extends ListActivity {
*/
}
private final class TOCAdapter extends ZLTreeAdapter {
private final ContentsTree myContentsTree;
private static final int PROCESS_TREE_ITEM_ID = 0;
private static final int READ_BOOK_ITEM_ID = 1;
TOCAdapter(ContentsTree tree) {
super(getListView(), tree);
myContentsTree = tree;
@Override
public boolean onContextItemSelected(MenuItem item) {
final int position = ((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).position;
final TOCTree tree = (TOCTree)myAdapter.getItem(position);
switch (item.getItemId()) {
case PROCESS_TREE_ITEM_ID:
myAdapter.runTreeItem(tree);
return true;
case READ_BOOK_ITEM_ID:
myAdapter.openBookText(tree);
return true;
}
return super.onContextItemSelected(item);
}
private final class TOCAdapter extends ZLTreeAdapter {
private final TOCTree myRoot;
TOCAdapter(TOCTree root) {
super(getListView(), root);
myRoot = root;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
final int position = ((AdapterView.AdapterContextMenuInfo)menuInfo).position;
final TOCTree tree = (TOCTree)getItem(position);
if (tree.hasChildren()) {
menu.setHeaderTitle(tree.getText());
// TODO: use resources
menu.add(0, PROCESS_TREE_ITEM_ID, 0, isOpen(tree) ? "Collapse tree" : "Expand tree");
menu.add(0, READ_BOOK_ITEM_ID, 0, "Read book text");
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view = (convertView != null) ? convertView :
LayoutInflater.from(parent.getContext()).inflate(R.layout.toc_tree_item, parent, false);
final ZLStringTree tree = (ZLStringTree)getItem(position);
final TOCTree tree = (TOCTree)getItem(position);
setIcon((ImageView)view.findViewById(R.id.toc_tree_item_icon), tree);
((TextView)view.findViewById(R.id.toc_tree_item_text)).setText(tree.getText());
return view;
}
void openBookText(TOCTree tree) {
final TOCTree.Reference reference = tree.getReference();
if (reference != null) {
final FBReader fbreader = (FBReader)ZLApplication.Instance();
fbreader.BookTextView.gotoParagraphSafe(reference.Model, reference.ParagraphIndex);
finish();
}
}
@Override
protected boolean runTreeItem(ZLTree tree) {
if (super.runTreeItem(tree)) {
return true;
}
final ContentsTree.Reference reference = myContentsTree.getReference((ZLStringTree)tree);
final FBReader fbreader = (FBReader)ZLApplication.Instance();
fbreader.BookTextView.gotoParagraphSafe(reference.Model, reference.ParagraphIndex);
finish();
openBookText((TOCTree)tree);
return true;
}
}

View file

@ -29,7 +29,7 @@ import org.geometerplus.zlibrary.core.tree.ZLTree;
import org.geometerplus.zlibrary.ui.android.R;
abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemClickListener, View.OnCreateContextMenuListener, View.OnKeyListener {
abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemClickListener, View.OnCreateContextMenuListener {
private final ListView myParent;
private final ZLTree myTree;
private final ZLTree[] myItems;
@ -56,14 +56,52 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
myOpenItems.add(tree);
parent.setAdapter(this);
parent.setOnKeyListener(this);
parent.setOnItemClickListener(this);
parent.setOnCreateContextMenuListener(this);
}
public final void openTree(ZLTree tree) {
if (tree == null) {
return;
}
while (!myOpenItems.contains(tree)) {
myOpenItems.add(tree);
tree = tree.getParent();
}
}
protected final boolean isOpen(ZLTree tree) {
return myOpenItems.contains(tree);
}
public final void selectItem(ZLTree tree) {
if (tree == null) {
return;
}
openTree(tree.getParent());
int index = 0;
while (true) {
ZLTree<?> parent = tree.getParent();
if (parent == null) {
break;
}
for (ZLTree sibling : parent.subTrees()) {
if (sibling == tree) {
break;
}
index += getCount(sibling);
}
tree = parent;
++index;
}
if (index > 0) {
myParent.setSelection(index - 1);
}
}
private int getCount(ZLTree<?> tree) {
int count = 1;
if (myOpenItems.contains(tree)) {
if (isOpen(tree)) {
for (ZLTree subtree : tree.subTrees()) {
count += getCount(subtree);
}
@ -119,7 +157,7 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
if (!tree.hasChildren()) {
return false;
}
if (myOpenItems.contains(tree)) {
if (isOpen(tree)) {
myOpenItems.remove(tree);
} else {
myOpenItems.add(tree);
@ -136,38 +174,13 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
private boolean myContextMenuInProgress;
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
System.err.println("onCreateContextMenu");
menu.add("Item 0");
menu.add("Item 1");
menu.add("Item 2");
}
public final boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
switch (keyEvent.getAction()) {
case KeyEvent.ACTION_UP:
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
runTreeItem((ZLTree)((ListView)view).getSelectedItem());
return true;
case KeyEvent.KEYCODE_BACK:
return true;
}
break;
case KeyEvent.ACTION_DOWN:
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
return true;
}
break;
}
return false;
}
public abstract View getView(int position, View convertView, ViewGroup parent);
protected final void setIcon(ImageView imageView, ZLTree tree) {
if (tree.hasChildren()) {
if (myOpenItems.contains(tree)) {
if (isOpen(tree)) {
imageView.setImageResource(R.drawable.tree_icon_group_open);
} else {
imageView.setImageResource(R.drawable.tree_icon_group_closed);

View file

@ -26,13 +26,13 @@ import org.geometerplus.zlibrary.core.image.*;
import org.geometerplus.zlibrary.text.model.*;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.formats.*;
public final class BookModel {
public final BookDescription Description;
public final ZLTextPlainModel BookTextModel = new ZLTextPlainModel(65536, "/sdcard/Books/.FBReader", "cache");
public final ContentsTree ContentsTree = new ContentsTree();
public final TOCTree TOCTree = new TOCTree();
private final HashMap<String,ZLTextPlainModel> myFootnotes = new HashMap<String,ZLTextPlainModel>();
private final HashMap myInternalHyperlinks = new HashMap();

View file

@ -24,7 +24,6 @@ import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.image.ZLImage;
import org.geometerplus.zlibrary.text.model.*;
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
public class BookReader {
public final BookModel Model;
@ -46,11 +45,11 @@ public class BookReader {
private boolean myInsideTitle = false;
private boolean mySectionContainsRegularContents = false;
private ZLStringTree myCurrentContentsTree;
private TOCTree myCurrentContentsTree;
public BookReader(BookModel model) {
Model = model;
myCurrentContentsTree = model.ContentsTree;
myCurrentContentsTree = model.TOCTree;
}
private final void flushTextBufferToParagraph() {
@ -242,7 +241,7 @@ public class BookReader {
if (referenceNumber == -1) {
referenceNumber = textModel.getParagraphsNumber();
}
ZLStringTree parentTree = myCurrentContentsTree;
TOCTree parentTree = myCurrentContentsTree;
if (parentTree.getLevel() > 0) {
final ZLTextBuffer contentsBuffer = myContentsBuffer;
if (!contentsBuffer.isEmpty()) {
@ -254,14 +253,14 @@ public class BookReader {
} else {
myContentsBuffer.clear();
}
ZLStringTree tree = parentTree.createSubTree();
Model.ContentsTree.setReference(tree, myCurrentTextModel, referenceNumber);
TOCTree tree = parentTree.createSubTree();
tree.setReference(myCurrentTextModel, referenceNumber);
myCurrentContentsTree = tree;
}
}
public final void endContentsParagraph() {
final ZLStringTree tree = myCurrentContentsTree;
final TOCTree tree = myCurrentContentsTree;
final ZLTextBuffer contentsBuffer = myContentsBuffer;
if (tree.getLevel() == 0) {
contentsBuffer.clear();
@ -281,10 +280,10 @@ public class BookReader {
}
public final void setReference(int contentsParagraphNumber, ZLTextModel textModel, int referenceNumber) {
final ContentsTree contentsTree = Model.ContentsTree;
final TOCTree contentsTree = Model.TOCTree;
if (contentsParagraphNumber < contentsTree.getSize()) {
contentsTree.setReference(
contentsTree.getTree(contentsParagraphNumber), textModel, referenceNumber
contentsTree.getTree(contentsParagraphNumber).setReference(
textModel, referenceNumber
);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
* Copyright (C) 2009 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
@ -19,21 +19,42 @@
package org.geometerplus.fbreader.bookmodel;
import java.util.*;
import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.tree.ZLTree;
import org.geometerplus.zlibrary.text.model.ZLTextModel;
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
public class ContentsTree extends ZLStringTree {
private final HashMap<ZLStringTree,Reference> myReferenceByTree = new HashMap<ZLStringTree,Reference>();
public class TOCTree extends ZLTree<TOCTree> {
private String myText;
private Reference myReference;
public Reference getReference(ZLStringTree tree) {
return myReferenceByTree.get(tree);
protected TOCTree() {
super();
}
public void setReference(ZLStringTree tree, ZLTextModel model, int reference) {
myReferenceByTree.put(tree, new Reference(reference, model));
private TOCTree(TOCTree parent) {
super(parent);
}
public final String getText() {
return myText;
}
public final void setText(String text) {
myText = text;
}
public Reference getReference() {
return myReference;
}
public void setReference(ZLTextModel model, int reference) {
myReference = new Reference(reference, model);
}
public final TOCTree createSubTree() {
TOCTree subtree = new TOCTree(this);
addSubTree(subtree);
return subtree;
}
public static class Reference {

View file

@ -1,167 +0,0 @@
/*
* Copyright (C) 2009 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.booksdb;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
public final class BookInfo {
private static boolean equals(Object o0, Object o1) {
if (o0 == null) {
return o1 == null;
}
return o0.equals(o1);
}
private final SQLiteDatabase myDatabase = BooksDatabase.Instance().Database;
private String myBookId;
public final String FileName;
private String myTitle;
private String myAuthorName;
private String myAuthorSortKey;
private String myLanguage;
private String myEncoding;
private String mySeries;
private int myNumberInSeries;
private boolean myIsSaved;
private boolean myIsChanged;
public BookInfo(String fileName) {
FileName = fileName;
// TODO: implement
myTitle = "";
myLanguage = "";
myEncoding = "";
myAuthorName = "";
myAuthorSortKey = "";
myIsSaved = false;
}
public boolean isSaved() {
return myIsSaved;
}
public void save() {
if (myIsChanged) {
// TODO: implement
myIsChanged = false;
//myIsSaved = true;
}
}
public void reset() {
final String whereClause = "book_id = ?";
final String[] parameters = new String[] { myBookId };
myDatabase.delete("Books", whereClause, parameters);
myDatabase.delete("BookAuthor", whereClause, parameters);
myDatabase.delete("BookSeries", whereClause, parameters);
myDatabase.delete("BookTag", whereClause, parameters);
myTitle = "";
myLanguage = "";
myEncoding = "";
myAuthorName = "";
myAuthorSortKey = "";
mySeries = null;
myNumberInSeries = 0;
myIsChanged = false;
myIsSaved = false;
}
public String getTitle() {
return myTitle;
}
public void setTitle(String title) {
if (!myTitle.equals(title)) {
myTitle = title;
myIsChanged = true;
}
}
public String getAuthorName() {
return myAuthorName;
}
public void setAuthorName(String authorName) {
if (!myAuthorName.equals(authorName)) {
myAuthorName = authorName;
myIsChanged = true;
}
}
public String getAuthorSortKey() {
return myAuthorSortKey;
}
public void setAuthorSortKey(String authorSortKey) {
if (!myAuthorSortKey.equals(authorSortKey)) {
myAuthorSortKey = authorSortKey;
myIsChanged = true;
}
}
public String getLanguage() {
return myLanguage;
}
public void setLanguage(String language) {
if (!myLanguage.equals(language)) {
myLanguage = language;
myIsChanged = true;
}
}
public String getEncoding() {
return myEncoding;
}
public void setEncoding(String encoding) {
if (!myEncoding.equals(encoding)) {
myEncoding = encoding;
myIsChanged = true;
}
}
public String getSeries() {
return mySeries;
}
public void setSeries(String series) {
if (!equals(mySeries, series)) {
mySeries = series;
myIsChanged = true;
}
}
public int getNumberInSeries() {
return myNumberInSeries;
}
public void setNumberInSeries(int numberInSeries) {
if (myNumberInSeries != numberInSeries) {
myNumberInSeries = numberInSeries;
myIsChanged = true;
}
}
}

View file

@ -1,96 +0,0 @@
/*
* Copyright (C) 2009 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.booksdb;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication;
class BooksDatabase {
private static BooksDatabase ourInstance;
static BooksDatabase Instance() {
if (ourInstance == null) {
ourInstance = new BooksDatabase(ZLAndroidApplication.Instance());
}
return ourInstance;
}
final SQLiteDatabase Database;
private BooksDatabase(Context context) {
Database = context.openOrCreateDatabase("books.db", Context.MODE_PRIVATE, null);
if (Database.getVersion() == 0) {
Database.beginTransaction();
/*
Database.execSQL("DROP TABLE Books");
Database.execSQL("DROP TABLE Authors");
Database.execSQL("DROP TABLE Series");
Database.execSQL("DROP TABLE Tags");
Database.execSQL("DROP TABLE BookAuthor");
Database.execSQL("DROP TABLE BookSeries");
Database.execSQL("DROP TABLE BookTag");
*/
Database.execSQL(
"CREATE TABLE Books(" +
"book_id INTEGER PRIMARY KEY," +
"encoding TEXT," +
"lenguage TEXT," +
"title TEXT NOT NULL," +
"file_name TEXT UNIQUE NOT NULL)");
Database.execSQL(
"CREATE TABLE Authors(" +
"author_id INTEGER PRIMARY KEY," +
"name TEXT NOT NULL," +
"sort_key TEXT NOT NULL," +
"CONSTRAINT Authors_Unique UNIQUE (name, sort_key))");
Database.execSQL(
"CREATE TABLE BookAuthor(" +
"author_id INTEGER NOT NULL REFERENCES Authors(author_id)," +
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
"CONSTRAINT BookAuthor_Unique UNIQUE (author_id, book_id))");
Database.execSQL(
"CREATE TABLE Series(" +
"series_id INTEGER PRIMARY KEY," +
"name TEXT UNIQUE NOT NULL)");
Database.execSQL(
"CREATE TABLE BookSeries(" +
"series_id INTEGER NOT NULL REFERENCES Series(series_id)," +
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
"number_in_series INTEGER," +
"CONSTRAINT BookSeries_Unique UNIQUE (series_id, book_id))");
Database.execSQL(
"CREATE TABLE Tags(" +
"tag_id INTEGER PRIMARY KEY," +
"name TEXT NOT NULL," +
"parent INTEGER REFERENCES Tags(tag_id)," +
"CONSTRAINT Tags_Unique UNIQUE (name, parent))");
Database.execSQL(
"CREATE TABLE BookTag(" +
"tag_id INTEGER REFERENCES Tags(tag_id)," +
"book_id INTEGER REFERENCES Books(book_id)," +
"CONSTRAINT BookTag_Unique UNIQUE (tag_id, book_id))");
Database.setTransactionSuccessful();
Database.endTransaction();
Database.setVersion(1);
}
}
}

View file

@ -17,7 +17,7 @@
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.description;
package org.geometerplus.fbreader.collection;
import java.util.*;
import org.geometerplus.zlibrary.core.util.*;
@ -26,15 +26,12 @@ public final class Author {
public final String DisplayName;
public final String SortKey;
Author(String displayName, String sortKey) {
public Author(String displayName, String sortKey) {
DisplayName = displayName;
SortKey = sortKey;
}
Author() {
this("Unknown Author", "___");
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
@ -46,6 +43,7 @@ public final class Author {
return SortKey.equals(a.SortKey) && DisplayName.equals(a.DisplayName);
}
@Override
public int hashCode() {
return SortKey.hashCode() + DisplayName.hashCode();
}

View file

@ -19,8 +19,6 @@
package org.geometerplus.fbreader.collection;
import org.geometerplus.fbreader.description.Author;
public class AuthorTree extends CollectionTree {
private final Author myAuthor;
@ -36,10 +34,11 @@ public class AuthorTree extends CollectionTree {
}
public String getName() {
return myAuthor.DisplayName;
// TODO: use resources
return (myAuthor != null) ? myAuthor.DisplayName : "Unknown Author";
}
protected String getSortKey() {
return myAuthor.SortKey;
return (myAuthor != null) ? myAuthor.SortKey : null;
}
}

View file

@ -22,10 +22,8 @@ package org.geometerplus.fbreader.collection;
import java.util.*;
import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.config.ZLConfig;
import org.geometerplus.zlibrary.core.filesystem.*;
import org.geometerplus.fbreader.description.*;
import org.geometerplus.fbreader.formats.PluginCollection;
public class BookCollection {
@ -115,51 +113,63 @@ public class BookCollection {
}
}
private static final ArrayList ourNullList = new ArrayList(1);
static {
ourNullList.add(null);
}
private TagTree getTagTree(Tag tag, HashMap<Tag,TagTree> tagTreeMap) {
TagTree tagTree = tagTreeMap.get(tag);
if (tagTree == null) {
CollectionTree parent =
((tag != null) && (tag.Parent != null)) ?
getTagTree(tag.Parent, tagTreeMap) : myCollectionByTag;
tagTree = parent.createTagSubTree(tag);
tagTreeMap.put(tag, tagTree);
}
return tagTree;
}
private void build() {
final HashSet fileNamesSet = collectBookFileNames();
final HashMap<String,TagTree> tagTreeMap = new HashMap<String,TagTree>();
final HashMap<Tag,TagTree> tagTreeMap = new HashMap<Tag,TagTree>();
final HashMap<Author,AuthorTree> authorTreeMap = new HashMap<Author,AuthorTree>();
final HashMap<AuthorSeriesPair,SeriesTree> seriesTreeMap = new HashMap<AuthorSeriesPair,SeriesTree>();
for (Iterator it = fileNamesSet.iterator(); it.hasNext(); ) {
final BookDescription description = BookDescription.getDescription((String)it.next());
final Author author = description.getAuthor();
final String series = description.getSeriesName();
AuthorTree authorTree = authorTreeMap.get(author);
if (authorTree == null) {
authorTree = myCollectionByAuthor.createAuthorSubTree(author);
authorTreeMap.put(author, authorTree);
List<Author> authors = description.authors();
if (authors.isEmpty()) {
authors = (List<Author>)ourNullList;
}
if (series.length() == 0) {
authorTree.createBookSubTree(description);
} else {
final AuthorSeriesPair pair = new AuthorSeriesPair(author, series);
SeriesTree seriesTree = seriesTreeMap.get(pair);
if (seriesTree == null) {
seriesTree = authorTree.createSeriesSubTree(series);
seriesTreeMap.put(pair, seriesTree);
final SeriesInfo seriesInfo = description.getSeriesInfo();
for (Author a : authors) {
AuthorTree authorTree = authorTreeMap.get(a);
if (authorTree == null) {
authorTree = myCollectionByAuthor.createAuthorSubTree(a);
authorTreeMap.put(a, authorTree);
}
if (seriesInfo == null) {
authorTree.createBookSubTree(description);
} else {
final String series = seriesInfo.Name;
final AuthorSeriesPair pair = new AuthorSeriesPair(a, series);
SeriesTree seriesTree = seriesTreeMap.get(pair);
if (seriesTree == null) {
seriesTree = authorTree.createSeriesSubTree(series);
seriesTreeMap.put(pair, seriesTree);
}
seriesTree.createBookInSeriesSubTree(description);
}
seriesTree.createBookInSeriesSubTree(description);
}
final List<String> tags = description.getTags();
if (!tags.isEmpty()) {
for (String tag : description.getTags()) {
TagTree tagTree = tagTreeMap.get(tag);
if (tagTree == null) {
tagTree = myCollectionByTag.createTagSubTree(tag);
tagTreeMap.put(tag, tagTree);
}
tagTree.createBookSubTree(description);
}
} else {
TagTree tagTree = tagTreeMap.get(null);
if (tagTree == null) {
tagTree = myCollectionByTag.createTagSubTree(null);
tagTreeMap.put(null, tagTree);
}
tagTree.createBookSubTree(description);
List<Tag> tags = description.tags();
if (tags.isEmpty()) {
tags = (List<Tag>)ourNullList;
}
for (Tag t : tags) {
getTagTree(t, tagTreeMap).createBookSubTree(description);
}
}
}
@ -169,7 +179,7 @@ public class BookCollection {
myCollectionByAuthor.clear();
myCollectionByTag.clear();
ZLConfig.Instance().executeAsATransaction(new Runnable() {
BooksDatabase.Instance().executeAsATransaction(new Runnable() {
public void run() {
build();
}

View file

@ -0,0 +1,257 @@
/*
* Copyright (C) 2007-2009 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.collection;
import java.util.*;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.formats.*;
public class BookDescription {
public final String FileName;
private long myBookId;
private String myEncoding;
private String myLanguage;
private String myTitle;
private ArrayList<Author> myAuthors;
private ArrayList<Tag> myTags;
private SeriesInfo mySeriesInfo;
private boolean myIsSaved;
private boolean myIsChanged;
private final static HashMap<String,BookDescription> ourDescriptions = new HashMap<String,BookDescription>();
public static BookDescription getDescription(String fileName) {
return getDescription(fileName, true);
}
public static BookDescription getDescription(String fileName, boolean checkFile) {
if (fileName == null) {
return null;
}
String physicalFileName = new ZLFile(fileName).getPhysicalFilePath();
ZLFile file = new ZLFile(physicalFileName);
if (checkFile && !file.exists()) {
return null;
}
BookDescription description = ourDescriptions.get(fileName);
if (description == null) {
description = new BookDescription(fileName);
ourDescriptions.put(fileName, description);
}
if ((!checkFile || BookDescriptionUtil.checkInfo(file)) && description.isSaved()) {
return description;
}
if (physicalFileName != fileName) {
BookDescriptionUtil.resetZipInfo(file);
}
BookDescriptionUtil.saveInfo(file);
ZLFile bookFile = new ZLFile(fileName);
FormatPlugin plugin = PluginCollection.instance().getPlugin(bookFile, false);
if ((plugin == null) || !plugin.readDescription(fileName, description)) {
return null;
}
String title = description.getTitle();
if ((title == null) || (title.length() == 0)) {
description.setTitle(bookFile.getName(true));
}
description.save();
return description;
}
private BookDescription(String fileName) {
FileName = fileName;
final BooksDatabase database = BooksDatabase.Instance();
myBookId = database.loadBook(this);
if (myBookId >= 0) {
myAuthors = database.loadAuthors(myBookId);
myTags = database.loadTags(myBookId);
mySeriesInfo = database.loadSeriesInfo(myBookId);
myIsSaved = true;
myIsChanged = false;
}
}
public boolean isSaved() {
return myIsSaved;
}
public List<Author> authors() {
return (myAuthors != null) ? Collections.unmodifiableList(myAuthors) : Collections.<Author>emptyList();
}
private void addAuthor(Author author) {
if (author == null) {
return;
}
if (myAuthors == null) {
myAuthors = new ArrayList<Author>();
myAuthors.add(author);
myIsChanged = true;
} else {
if (!myAuthors.contains(author)) {
myAuthors.add(author);
myIsChanged = true;
}
}
}
public void addAuthor(String name) {
addAuthor(name, "");
}
public void addAuthor(String name, String sortKey) {
String strippedName = name;
strippedName.trim();
if (strippedName.length() == 0) {
return;
}
String strippedKey = sortKey;
strippedKey.trim();
if (strippedKey.length() == 0) {
int index = strippedName.lastIndexOf(' ');
if (index == -1) {
strippedKey = strippedName;
} else {
strippedKey = strippedName.substring(index + 1);
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
--index;
}
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
}
}
addAuthor(new Author(strippedName, strippedKey));
}
public String getTitle() {
return myTitle;
}
public void setTitle(String title) {
if (!equals(myTitle, title)) {
myTitle = title;
myIsChanged = true;
}
}
public SeriesInfo getSeriesInfo() {
return mySeriesInfo;
}
public void setSeriesInfo(String name, long index) {
if (mySeriesInfo == null) {
if (name != null) {
mySeriesInfo = new SeriesInfo(name, index);
}
} else if (name == null) {
mySeriesInfo = null;
} else if (!mySeriesInfo.Name.equals(name) || (mySeriesInfo.Index != index)) {
mySeriesInfo = new SeriesInfo(name, index);
}
}
public String getLanguage() {
return myLanguage;
}
public void setLanguage(String language) {
if (!equals(myLanguage, language)) {
myLanguage = language;
myIsChanged = true;
}
}
public String getEncoding() {
return myEncoding;
}
public void setEncoding(String encoding) {
if (!equals(myEncoding, encoding)) {
myEncoding = encoding;
myIsChanged = true;
}
}
public List<Tag> tags() {
return (myTags != null) ? Collections.unmodifiableList(myTags) : Collections.<Tag>emptyList();
}
public void addTag(Tag tag) {
if (tag != null) {
if (myTags == null) {
myTags = new ArrayList<Tag>();
}
if (!myTags.contains(tag)) {
myTags.add(tag);
myIsChanged = true;
}
}
}
public void addTag(String tagName) {
addTag(Tag.getTag(null, tagName));
}
private void save() {
if (!myIsChanged) {
return;
}
final BooksDatabase database = BooksDatabase.Instance();
database.executeAsATransaction(new Runnable() {
public void run() {
if (myBookId >= 0) {
database.updateBookInfo(myBookId, myEncoding, myLanguage, myTitle);
} else {
myBookId = database.insertBookInfo(FileName, myEncoding, myLanguage, myTitle);
}
long index = 0;
for (Author author : authors()) {
database.saveBookAuthorInfo(myBookId, index++, author);
}
for (Tag tag : tags()) {
database.saveBookTagInfo(myBookId, tag);
}
database.saveBookSeriesInfo(myBookId, mySeriesInfo);
}
});
myIsChanged = false;
myIsSaved = true;
}
private static boolean equals(Object o0, Object o1) {
if (o0 == null) {
return o1 == null;
}
return o0.equals(o1);
}
}

View file

@ -17,18 +17,18 @@
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.description;
package org.geometerplus.fbreader.collection;
import java.util.*;
import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.fbreader.description.BookDescription.BookInfo;
import org.geometerplus.fbreader.formats.PluginCollection;
import org.geometerplus.zlibrary.core.filesystem.ZLDir;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.options.ZLIntegerOption;
import org.geometerplus.zlibrary.core.options.ZLStringOption;
import org.geometerplus.fbreader.formats.PluginCollection;
public class BookDescriptionUtil {
private static final String SIZE = "Size";
private static final String ENTRY = "Entry";
@ -37,7 +37,6 @@ public class BookDescriptionUtil {
public static boolean checkInfo(ZLFile file) {
ZLIntegerOption op = new ZLIntegerOption(file.getPath(), SIZE, -1);
return op.getValue() == (int)file.size();
}
public static void saveInfo(ZLFile file) {
@ -47,7 +46,6 @@ public class BookDescriptionUtil {
public static void listZipEntries(ZLFile zipFile, ArrayList entries) {
int entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
if (entriesNumber == -1) {
//??? why so??resetZipInfo(zipFile.path());
resetZipInfo(zipFile);
entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
}
@ -60,7 +58,6 @@ public class BookDescriptionUtil {
entries.add(entry);
}
}
}
public static void resetZipInfo(ZLFile zipFile) {
@ -80,36 +77,11 @@ public class BookDescriptionUtil {
final String fullName = zipPrefix + entry;
entryOption.changeName(ENTRY + counter);
entryOption.setValue(fullName);
new BookInfo(fullName).reset();
BooksDatabase.Instance().resetBookInfo(fullName);
++counter;
}
}
new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).setValue(counter);
}
}
public static String removeWhiteSpacesFromTag(String tag) {
int index = tag.indexOf('/');
if (index == -1) {
return tag.trim();
} else {
final StringBuilder result = new StringBuilder();
int index0 = 0;
while (true) {
String subtag = (index == -1) ? tag.substring(index0).trim() : tag.substring(index0, index).trim();
if (subtag.length() > 0) {
if (result.length() > 0) {
result.append("/");
}
result.append(subtag);
}
if (index == -1) {
break;
}
index0 = index + 1;
index = tag.indexOf('/', index0);
}
return result.toString();
}
}
}

View file

@ -19,8 +19,6 @@
package org.geometerplus.fbreader.collection;
import org.geometerplus.fbreader.description.BookDescription;
public final class BookInSeriesTree extends BookTree {
BookInSeriesTree(CollectionTree parent, BookDescription description) {
super(parent, description);
@ -29,9 +27,10 @@ public final class BookInSeriesTree extends BookTree {
@Override
public int compareTo(CollectionTree tree) {
if (tree instanceof BookInSeriesTree) {
final int difference = Description.getNumberInSeries() - ((BookTree)tree).Description.getNumberInSeries();
final long difference =
Description.getSeriesInfo().Index - ((BookTree)tree).Description.getSeriesInfo().Index;
if (difference != 0) {
return difference;
return (int)difference;
}
}
return super.compareTo(tree);

View file

@ -19,8 +19,6 @@
package org.geometerplus.fbreader.collection;
import org.geometerplus.fbreader.description.BookDescription;
public class BookTree extends CollectionTree {
public final BookDescription Description;

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2009 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.collection;
import java.util.ArrayList;
public abstract class BooksDatabase {
private static BooksDatabase ourInstance;
static BooksDatabase Instance() {
return ourInstance;
}
protected BooksDatabase() {
ourInstance = this;
}
public abstract void executeAsATransaction(Runnable actions);
public abstract long loadBook(BookDescription description);
public abstract ArrayList<Author> loadAuthors(long bookId);
public abstract ArrayList<Tag> loadTags(long bookId);
public abstract SeriesInfo loadSeriesInfo(long bookId);
public abstract void updateBookInfo(long bookId, String encoding, String language, String title);
public abstract long insertBookInfo(String fileName, String encoding, String language, String title);
public abstract void saveBookAuthorInfo(long bookId, long index, Author author);
public abstract void saveBookTagInfo(long bookId, Tag tag);
public abstract void saveBookSeriesInfo(long bookId, SeriesInfo seriesInfo);
public abstract void resetBookInfo(String fileName);
}

View file

@ -23,8 +23,6 @@ import java.util.Collections;
import java.util.ArrayList;
import org.geometerplus.zlibrary.core.tree.ZLTree;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.description.Author;
public abstract class CollectionTree extends ZLTree<CollectionTree> implements Comparable<CollectionTree> {
protected CollectionTree() {
@ -35,7 +33,7 @@ public abstract class CollectionTree extends ZLTree<CollectionTree> implements C
super(parent);
}
TagTree createTagSubTree(String tag) {
TagTree createTagSubTree(Tag tag) {
TagTree tree = new TagTree(this, tag);
addSubTree(tree);
return tree;

View file

@ -25,7 +25,6 @@ import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.config.ZLConfig;
import org.geometerplus.zlibrary.core.options.ZLStringOption;
import org.geometerplus.fbreader.description.*;
import org.geometerplus.fbreader.formats.PluginCollection;
public final class RecentBooks {

View file

@ -17,32 +17,14 @@
* 02110-1301, USA.
*/
package org.geometerplus.zlibrary.core.tree;
package org.geometerplus.fbreader.collection;
import java.util.ArrayList;
public final class SeriesInfo {
public final String Name;
public final long Index;
public class ZLStringTree extends ZLTree<ZLStringTree> {
private String myText;
protected ZLStringTree() {
super();
}
private ZLStringTree(ZLStringTree parent) {
super(parent);
}
public final String getText() {
return myText;
}
public final void setText(String text) {
myText = text;
}
public final ZLStringTree createSubTree() {
ZLStringTree subtree = new ZLStringTree(this);
addSubTree(subtree);
return subtree;
public SeriesInfo(String name, long index) {
Name = name;
Index = index;
}
}

View file

@ -19,8 +19,6 @@
package org.geometerplus.fbreader.collection;
import org.geometerplus.fbreader.description.BookDescription;
final class SeriesTree extends CollectionTree {
private final String mySeries;

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2009 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.collection;
import java.util.HashMap;
public final class Tag {
private static final HashMap<Tag,Tag> ourTagSet = new HashMap<Tag,Tag>();
public static Tag getTag(Tag parent, String name) {
if (name == null) {
return parent;
}
name = name.trim();
if (name.length() == 0) {
return parent;
}
Tag tag = new Tag(parent, name);
Tag stored = ourTagSet.get(tag);
if (stored != null) {
return stored;
}
ourTagSet.put(tag, tag);
return tag;
}
public final Tag Parent;
public final String Name;
private Tag(Tag parent, String name) {
Parent = parent;
Name = name;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Tag)) {
return false;
}
Tag t = (Tag)o;
return (Parent == t.Parent) && Name.equals(t.Name);
}
@Override
public int hashCode() {
return (Parent == null) ? Name.hashCode() : Parent.hashCode() + Name.hashCode();
}
}

View file

@ -20,19 +20,19 @@
package org.geometerplus.fbreader.collection;
final class TagTree extends CollectionTree {
private final String myTag;
private final Tag myTag;
TagTree(CollectionTree parent, String tag) {
TagTree(CollectionTree parent, Tag tag) {
super(parent);
myTag = tag;
}
public String getName() {
// TODO: use resources
return (myTag != null) ? myTag : "Books with no tags";
return (myTag != null) ? myTag.Name : "Books with no tags";
}
protected String getSortKey() {
return myTag;
return (myTag != null) ? myTag.Name : null;
}
}

View file

@ -1,423 +0,0 @@
/*
* Copyright (C) 2007-2009 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.description;
import java.util.*;
import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.options.*;
import org.geometerplus.fbreader.formats.*;
public class BookDescription {
private static final String EMPTY = "";
private static final String UNKNOWN = "unknown";
public final String FileName;
//private final TreeSet<Author> myAuthors = new TreeSet<Author>();
private Author myAuthor;
private String myTitle = "";
private String mySeriesName = "";
private int myNumberInSeries = 0;
private String myLanguage = "";
private String myEncoding = "";
private final static HashMap ourDescriptions = new HashMap();
private final ArrayList<String> myTags = new ArrayList<String>();
public static BookDescription getDescription(String fileName) {
return getDescription(fileName, true);
}
public static BookDescription getDescription(String fileName, boolean checkFile) {
if (fileName == null) {
return null;
}
String physicalFileName = new ZLFile(fileName).getPhysicalFilePath();
ZLFile file = new ZLFile(physicalFileName);
if (checkFile && !file.exists()) {
return null;
}
BookDescription description = (BookDescription)ourDescriptions.get(fileName);
if (description == null) {
description = new BookDescription(fileName);
ourDescriptions.put(fileName, description);
}
if (!checkFile || BookDescriptionUtil.checkInfo(file)) {
//if (false) {
BookInfo info = new BookInfo(fileName);
description.myAuthor = new Author(info.AuthorDisplayNameOption.getValue(), info.AuthorSortKeyOption.getValue());
description.myTitle = info.TitleOption.getValue();
description.mySeriesName = info.SeriesNameOption.getValue();
description.myNumberInSeries = info.NumberInSeriesOption.getValue();
description.myLanguage = info.LanguageOption.getValue();
description.myEncoding = info.EncodingOption.getValue();
description.myTags.clear();
final String tagList = info.TagsOption.getValue();
if (tagList.length() > 0) {
int index = 0;
do {
final int newIndex = tagList.indexOf(',', index);
final String tagName = (newIndex == -1) ? tagList.substring(index) : tagList.substring(index, newIndex);
description.addTag(tagName, true);
index = newIndex + 1;
} while (index != 0);
}
if (info.isFull()) {
return description;
}
} else {
if (physicalFileName != fileName) {
BookDescriptionUtil.resetZipInfo(file);
}
BookDescriptionUtil.saveInfo(file);
}
ZLFile bookFile = new ZLFile(fileName);
FormatPlugin plugin = PluginCollection.instance().getPlugin(bookFile, false);
if ((plugin == null) || !plugin.readDescription(fileName, description)) {
return null;
}
if (description.myTitle.length() == 0) {
description.myTitle = bookFile.getName(true);
}
Author author = description.myAuthor;
if (author == null || author.DisplayName.length() == 0) {
description.myAuthor = new Author();
}
if (description.myEncoding.length() == 0) {
description.myEncoding = "auto";
}
{
BookInfo info = new BookInfo(fileName);
info.AuthorDisplayNameOption.setValue(description.myAuthor.DisplayName);
info.AuthorSortKeyOption.setValue(description.myAuthor.SortKey);
info.TitleOption.setValue(description.myTitle);
info.SeriesNameOption.setValue(description.mySeriesName);
info.NumberInSeriesOption.setValue(description.myNumberInSeries);
info.LanguageOption.setValue(description.myLanguage);
info.EncodingOption.setValue(description.myEncoding);
}
return description;
}
private BookDescription(String fileName) {
FileName = fileName;
myAuthor = null;
myNumberInSeries = 0;
}
public Author getAuthor() {
return myAuthor;
}
public String getTitle() {
return myTitle;
}
public String getSeriesName() {
return mySeriesName;
}
public int getNumberInSeries() {
return myNumberInSeries;
}
public String getLanguage() {
return myLanguage;
}
public String getEncoding() {
return myEncoding;
}
public List<String> getTags() {
return Collections.unmodifiableList(myTags);
}
private boolean addTag(String tag, boolean check) {
if (check) {
tag = BookDescriptionUtil.removeWhiteSpacesFromTag(tag);
}
if ((tag.length() > 0) && !myTags.contains(tag)) {
myTags.add(tag);
return true;
}
return false;
}
private void saveTags() {
saveTags(new ZLStringOption(FileName, "TagList", EMPTY));
}
private void saveTags(ZLStringOption tagsOption) {
final ArrayList<String> tags = myTags;
if (tags.isEmpty()) {
tagsOption.setValue("");
} else {
final StringBuilder tagString = new StringBuilder();
tagString.append(tags.get(0));
final int len = tags.size();
for (int i = 1; i < len; ++i) {
tagString.append(",");
tagString.append(tags.get(i));
}
tagsOption.setValue(tagString.toString());
}
}
public static class BookInfo {
public final ZLStringOption AuthorDisplayNameOption;
public final ZLStringOption AuthorSortKeyOption;
public final ZLStringOption TitleOption;
public final ZLStringOption SeriesNameOption;
public final ZLIntegerRangeOption NumberInSeriesOption;
public final ZLStringOption LanguageOption;
public final ZLStringOption EncodingOption;
public final ZLStringOption TagsOption;
public BookInfo(String fileName) {
AuthorDisplayNameOption = new ZLStringOption(fileName, "AuthorDisplayName", EMPTY);
AuthorSortKeyOption = new ZLStringOption(fileName, "AuthorSortKey", EMPTY);
TitleOption = new ZLStringOption(fileName, "Title", EMPTY);
SeriesNameOption = new ZLStringOption(fileName, "Sequence", EMPTY);
NumberInSeriesOption = new ZLIntegerRangeOption(fileName, "Number in seq", 0, 100, 0);
LanguageOption = new ZLStringOption(fileName, "Language", UNKNOWN);
EncodingOption = new ZLStringOption(fileName, "Encoding", EMPTY);
TagsOption = new ZLStringOption(fileName, "TagList", EMPTY);
}
public boolean isFull() {
return
(AuthorDisplayNameOption.getValue().length() != 0) &&
(AuthorSortKeyOption.getValue().length() != 0) &&
(TitleOption.getValue().length() != 0) &&
(EncodingOption.getValue().length() != 0);
}
void reset() {
AuthorDisplayNameOption.setValue(EMPTY);
AuthorSortKeyOption.setValue(EMPTY);
TitleOption.setValue(EMPTY);
SeriesNameOption.setValue(EMPTY);
NumberInSeriesOption.setValue(0);
LanguageOption.setValue(UNKNOWN);
EncodingOption.setValue(EMPTY);
TagsOption.setValue(EMPTY);
}
}
static public class WritableBookDescription {
private final BookDescription myDescription;
public WritableBookDescription(BookDescription description) {
myDescription = description;
}
public void addAuthor(String name) {
addAuthor(name, "");
}
public void addAuthor(String name, String sortKey) {
String strippedName = name;
strippedName.trim();
if (strippedName.length() == 0) {
return;
}
String strippedKey = sortKey;
strippedKey.trim();
if (strippedKey.length() == 0) {
int index = strippedName.lastIndexOf(' ');
if (index == -1) {
strippedKey = strippedName;
} else {
strippedKey = strippedName.substring(index + 1);
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
--index;
}
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
}
}
Author author = new Author(strippedName, strippedKey);
if (myDescription.myAuthor == null) {
myDescription.myAuthor = author;
} else {
// TODO: implement
}
}
public void clearAuthor() {
myDescription.myAuthor = null;
}
public Author getAuthor() {
return myDescription.getAuthor();
}
public String getTitle() {
return myDescription.myTitle;
}
public void setTitle(String title) {
myDescription.myTitle = title;
}
public String getSeriesName() {
return myDescription.mySeriesName;
}
public void setSeriesName(String sequenceName) {
myDescription.mySeriesName = sequenceName;
}
public int getNumberInSeries() {
return myDescription.myNumberInSeries;
}
public void setNumberInSeries(int numberInSeries) {
myDescription.myNumberInSeries = numberInSeries;
}
public String getFileName() {
return myDescription.FileName;
}
public String getLanguage() {
return myDescription.myLanguage;
}
public void setLanguage(String language) {
myDescription.myLanguage = language;
}
public String getEncoding() {
return myDescription.myEncoding;
}
public void setEncoding(String encoding) {
myDescription.myEncoding = encoding;
}
public void addTag(String tag, boolean check) {
if (myDescription.addTag(tag, check)) {
myDescription.saveTags();
}
}
public void removeTag(String tag, boolean includeSubTags) {
final ArrayList<String> tags = myDescription.myTags;
if (includeSubTags) {
final String prefix = tag + '/';
boolean changed = false;
final int len = tags.size();
ArrayList toRemove = null;
for (int i = 0; i < len; ++i) {
String current = tags.get(i);
if (current.equals(tag) || current.startsWith(prefix)) {
if (toRemove == null) {
toRemove = new ArrayList();
}
toRemove.add(i);
}
}
if (toRemove != null) {
for (int i = toRemove.size() - 1; i >= 0; --i) {
tags.remove(((Integer)toRemove.get(i)).intValue());
}
myDescription.saveTags();
}
} else {
if (tags.remove(tag)) {
myDescription.saveTags();
}
}
}
public void renameTag(String from, String to, boolean includeSubTags) {
final ArrayList<String> tags = myDescription.myTags;
if (includeSubTags) {
final String prefix = from + '/';
final HashSet tagSet = new HashSet();
boolean changed = false;
final int len = tags.size();
for (int i = 0; i < len; ++i) {
final String value = tags.get(i);
if (from.equals(value)) {
tagSet.add(to);
changed = true;
} else if (value.startsWith(prefix)) {
tagSet.add(to + '/' + value.substring(prefix.length()));
changed = true;
} else {
tagSet.add(value);
}
}
if (changed) {
tags.clear();
tags.addAll(tagSet);
myDescription.saveTags();
}
} else {
if (tags.remove(from) && !tags.contains(to)) {
tags.add(to);
myDescription.saveTags();
}
}
}
public void cloneTag(String from, String to, boolean includeSubTags) {
final ArrayList<String> tags = myDescription.myTags;
if (includeSubTags) {
final String prefix = from + '/';
final HashSet tagSet = new HashSet();
final int len = tags.size();
for (int i = 0; i < len; ++i) {
final String value = tags.get(i);
if (value.equals(from)) {
tagSet.add(to);
} else if (value.startsWith(prefix)) {
tagSet.add(to + '/' + value.substring(prefix.length()));
}
}
if (!tagSet.isEmpty()) {
tagSet.addAll(tags);
tags.clear();
tags.addAll(tagSet);
myDescription.saveTags();
}
} else {
if (tags.contains(from) && !tags.contains(to)) {
tags.add(to);
myDescription.saveTags();
}
}
}
public void removeAllTags() {
myDescription.myTags.clear();
}
};
}

View file

@ -40,7 +40,6 @@ public interface ActionCode {
String DECREASE_FONT = "decreaseFont";
String TOGGLE_FULLSCREEN = "toggleFullscreen";
String FULLSCREEN_ON = "onFullscreen";
String SHOW_BOOK_INFO = "bookInfo";
String SHOW_HELP = "showHelp";
String ROTATE_SCREEN = "rotate";
String QUIT = "quit";

View file

@ -1,215 +0,0 @@
/*
* Copyright (C) 2007-2009 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.fbreader;
import java.util.*;
import org.geometerplus.zlibrary.core.dialogs.*;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.language.ZLLanguageList;
import org.geometerplus.zlibrary.core.optionEntries.*;
import org.geometerplus.fbreader.collection.BookCollection;
import org.geometerplus.fbreader.description.*;
import org.geometerplus.fbreader.formats.*;
import org.geometerplus.fbreader.encodingOption.*;
import org.geometerplus.fbreader.encodingOption.EncodingEntry;
public class BookInfoDialog {
private final ZLOptionsDialog myDialog;
private final BookCollection myCollection;
// private final BookDescription.BookInfo myBookInfo;
// private FormatInfoPage myFormatInfoPage;
private AuthorDisplayNameEntry myAuthorDisplayNameEntry;
private AuthorSortKeyEntry myAuthorSortKeyEntry;
private ZLComboOptionEntry myEncodingSetEntry;
private ZLComboOptionEntry myEncodingEntry;
private ZLComboOptionEntry myLanguageEntry;
private SeriesTitleEntry mySeriesTitleEntry;
private ZLSpinOptionEntry myBookNumberEntry;
//private FormatInfoPage myFormatInfoPage;
public BookInfoDialog(String fileName, Runnable actionOnAccept) {
myCollection = BookCollection.Instance();
//myBookInfo = new BookDescription.BookInfo(fileName);
myDialog = ZLDialogManager.getInstance().createOptionsDialog("InfoDialog", actionOnAccept, null, false);
ZLDialogContent commonTab = myDialog.createTab("Common");
commonTab.addOption("file", new ZLStringInfoEntry(new ZLFile(fileName).getPath()));
//commonTab.addOption("title", myBookInfo.TitleOption);
myAuthorDisplayNameEntry = new AuthorDisplayNameEntry();
myAuthorSortKeyEntry = new AuthorSortKeyEntry();
//myEncodingEntry = new EncodingEntry(myBookInfo.EncodingOption);
myEncodingSetEntry =
(!"auto".equals(myEncodingEntry.initialValue())) ?
new EncodingSetEntry((EncodingEntry)myEncodingEntry) : null;
ArrayList/*<std::string>*/ languageCodes = ZLLanguageList.languageCodes();
languageCodes.add("de-traditional");
//myLanguageEntry = new ZLLanguageOptionEntry(myBookInfo.LanguageOption, languageCodes);
mySeriesTitleEntry = new SeriesTitleEntry();
//myBookNumberEntry = new ZLSimpleSpinOptionEntry(myBookInfo.NumberInSeriesOption, 1);
commonTab.addOption("authorDisplayName", myAuthorDisplayNameEntry);
commonTab.addOption("authorSortKey", myAuthorSortKeyEntry);
commonTab.addOption("language", myLanguageEntry);
if (myEncodingSetEntry != null) {
commonTab.addOption("encodingSet", myEncodingSetEntry);
}
commonTab.addOption("encoding", myEncodingEntry);
ZLDialogContent seriesTab = myDialog.createTab("Series");
seriesTab.addOption("seriesTitle", mySeriesTitleEntry);
seriesTab.addOption("bookNumber", myBookNumberEntry);
mySeriesTitleEntry.onValueEdited(mySeriesTitleEntry.initialValue());
ZLDialogContent tagsTab = myDialog.createTab("Tags");
//tagsTab.addOption("tags", myBookInfo.TagsOption);
//FormatPlugin plugin = PluginCollection.instance().getPlugin(new ZLFile(fileName), false);
//if (plugin != null) {
//myFormatInfoPage = plugin.createInfoPage(myDialog, fileName);
//}
}
public ZLOptionsDialog getDialog() {
return myDialog;
}
private class AuthorSortKeyEntry extends ZLStringOptionEntry {
public String initialValue() {
Author currentAuthor = myAuthorDisplayNameEntry.myCurrentAuthor;
return //currentAuthor == null ?
//myBookInfo.AuthorSortKeyOption.getValue() :
currentAuthor.SortKey;
}
public void onAccept(String value) {
//myBookInfo.AuthorSortKeyOption.setValue(value);
}
}
private class AuthorDisplayNameEntry extends ZLComboOptionEntry {
private final ArrayList myValues = new ArrayList();
private Author myCurrentAuthor;
public AuthorDisplayNameEntry() {
super(true);
}
public ArrayList getValues() {
if (myValues.size() == 0) {
final String initial = initialValue();
boolean addInitial = true;
/*
for (Author author : myCollection.authors()) {
final String name = author.DisplayName;
if (addInitial && name.equals(initial)) {
addInitial = false;
}
myValues.add(name);
}
*/
if (addInitial) {
myValues.add(initial);
}
}
return myValues;
}
public String initialValue() {
return "";//myBookInfo.AuthorDisplayNameOption.getValue();
}
public void onAccept(String value) {
//myBookInfo.AuthorDisplayNameOption.setValue(value);
}
public void onValueSelected(int index) {
/*
final Collection<Author> authors = myCollection.authors();
if (index < authors.size()) {
myCurrentAuthor = new ArrayList<Author>(authors).get(index);
}
*/
myAuthorSortKeyEntry.resetView();
mySeriesTitleEntry.resetView();
}
}
private class SeriesTitleEntry extends ZLComboOptionEntry {
private final ArrayList myValues = new ArrayList();
private Author myOriginalAuthor;
public SeriesTitleEntry() {
super(true);
final String authorName = "";//myBookInfo.AuthorDisplayNameOption.getValue();
final String authorKey = "";//myBookInfo.AuthorSortKeyOption.getValue();
/*
for (Author author : myCollection.authors()) {
if ((authorName != null && authorName.equals(author.DisplayName)) &&
(authorKey != null && authorKey.equals(author.SortKey))) {
myOriginalAuthor = author;
break;
}
}
*/
}
public boolean useOnValueEdited() {
return true;
}
public void onValueEdited(String value) {
myBookNumberEntry.setVisible(value != null && !value.equals(""));;
}
public void onValueSelected(int index) {
myBookNumberEntry.setVisible(index != 0);
}
public ArrayList getValues() {
myValues.clear();
HashSet valuesSet = new HashSet();
valuesSet.add(initialValue());
valuesSet.add("");
if (myOriginalAuthor != null) {
//myCollection.collectSeriesNames(myOriginalAuthor, valuesSet);
}
Author currentAuthor = myAuthorDisplayNameEntry.myCurrentAuthor;
if (currentAuthor != null && (currentAuthor != myOriginalAuthor)) {
//myCollection.collectSeriesNames(currentAuthor, valuesSet);
}
myValues.addAll(valuesSet);
return myValues;
}
public String initialValue() {
return "";//myBookInfo.SeriesNameOption.getValue();
}
public void onAccept(String value) {
//myBookInfo.SeriesNameOption.setValue(value);
}
}
}

View file

@ -38,7 +38,7 @@ import org.geometerplus.zlibrary.text.hyphenation.ZLTextHyphenator;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.collection.BookCollection;
import org.geometerplus.fbreader.collection.RecentBooks;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
public final class FBReader extends ZLApplication {
static interface ViewMode {
@ -108,7 +108,6 @@ public final class FBReader extends ZLApplication {
addAction(ActionCode.SHOW_LIBRARY, new ShowLibrary(this));
addAction(ActionCode.SHOW_OPTIONS, new ShowOptionsDialogAction(this));
addAction(ActionCode.SHOW_CONTENTS, new ShowTOCAction(this));
addAction(ActionCode.SHOW_BOOK_INFO, new ShowBookInfoDialogAction(this));
addAction(ActionCode.SEARCH, new SearchAction(this));
addAction(ActionCode.FIND_NEXT, new FindNextAction(this));
@ -239,13 +238,10 @@ public final class FBReader extends ZLApplication {
BookTextView.setModels(null, "");
Model = null;
//android.os.Debug.startMethodTracing("/data/anr/loading");
Model = new BookModel(description);
//android.os.Debug.stopMethodTracing();
final String fileName = description.FileName;
myBookNameOption.setValue(fileName);
ZLTextHyphenator.getInstance().load(description.getLanguage());
// BookTextView.setModel(Model.BookTextModel, fileName);
BookTextView.setModels(Model.getBookTextModels(), fileName);
BookTextView.setCaption(description.getTitle());
FootnoteView.setModel(null);
@ -268,9 +264,7 @@ public final class FBReader extends ZLApplication {
}
public void run() {
//final long start = System.currentTimeMillis();
openBookInternal(myDescription);
//android.util.Log.w("openBook", "" + (System.currentTimeMillis() - start));
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2007-2009 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.fbreader;
import org.geometerplus.fbreader.collection.BookCollection;
class ShowBookInfoDialogAction extends FBAction {
ShowBookInfoDialogAction(FBReader fbreader) {
super(fbreader);
}
public boolean isVisible() {
return Reader.getMode() == FBReader.ViewMode.BOOK_TEXT;
}
public void run() {
final String fileName = Reader.BookTextView.getFileName();
Runnable action = new Runnable() {
public void run() {
Reader.openFile(fileName);
Reader.refreshWindow();
}
};
new BookInfoDialog(fileName, action).getDialog().run();
}
}

View file

@ -19,7 +19,7 @@
package org.geometerplus.fbreader.fbreader;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
class ShowHelpAction extends FBAction {
ShowHelpAction(FBReader fbreader) {

View file

@ -29,7 +29,7 @@ class ShowTOCAction extends FBAction {
}
public boolean isVisible() {
return Reader.Model.ContentsTree.hasChildren();
return Reader.Model.TOCTree.hasChildren();
}
public void run() {

View file

@ -23,8 +23,7 @@ import java.io.*;
import java.util.*;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.zlibrary.core.dialogs.ZLOptionsDialog;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.language.ZLLanguageDetector;
@ -72,8 +71,8 @@ public abstract class FormatPlugin {
}
}
}
new WritableBookDescription(description).setEncoding(encoding);
new WritableBookDescription(description).setLanguage(language);
description.setEncoding(encoding);
description.setLanguage(language);
}
}
//Last working version
@ -84,24 +83,24 @@ public abstract class FormatPlugin {
if (encoding == "unknown") {
encoding = "windows-1252";
}
new WritableBookDescription(description).setEncoding(encoding);
description.setEncoding(encoding);
}
if (description.getLanguage() == "") {
if ((encoding.equals("US-ASCII")) ||
(encoding.equals("ISO-8859-1"))) {
new WritableBookDescription(description).setLanguage("en");
description.setLanguage("en");
} else if ((description.getEncoding().equals("KOI8-R")) ||
(encoding.equals("windows-1251")) ||
(encoding.equals("ISO-8859-5")) ||
(encoding.equals("IBM866"))) {
new WritableBookDescription(description).setLanguage("ru");
description.setLanguage("ru");
} /*else if (
(PluginCollection.instance().DefaultLanguageOption.getValue() == EncodingDetector.Language.CZECH) &&
((encoding == "windows-1250") ||
(encoding == "ISO-8859-2") ||
(encoding == "IBM852"))) {
new WritableBookDescription(description).setLanguage("cs");
description.setLanguage("cs");
}*/
/*}

View file

@ -23,8 +23,8 @@ import java.util.*;
import org.geometerplus.zlibrary.core.xml.*;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.collection.Tag;
public class FB2DescriptionReader extends ZLXMLReaderAdapter {
private final static int READ_NOTHING = 0;
@ -37,18 +37,16 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
private final static int READ_LANGUAGE = 7;
private final static int READ_GENRE = 8;
private WritableBookDescription myDescription;
private final BookDescription myDescription;
private int myReadState = READ_NOTHING;
private final String[] myAuthorNames = new String[3];
private final StringBuilder myGenreBuffer = new StringBuilder();
private final StringBuilder myBuffer = new StringBuilder();
public FB2DescriptionReader(BookDescription description) {
myDescription = new WritableBookDescription(description);
myDescription.clearAuthor();
myDescription.setTitle("");
myDescription.setLanguage("");
myDescription.removeAllTags();
myDescription = description;
myDescription.setTitle(null);
myDescription.setLanguage(null);
}
public boolean dontCacheAttributeValues() {
@ -60,7 +58,7 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
myAuthorNames[0] = "";
myAuthorNames[1] = "";
myAuthorNames[2] = "";
myGenreBuffer.delete(0, myGenreBuffer.length());
myBuffer.delete(0, myBuffer.length());
return readDocument(fileName);
}
@ -110,11 +108,11 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
if (myReadState == READ_SOMETHING) {
String name = attributes.getValue("name");
if (name != null) {
String sequenceName = name;
sequenceName.trim();
myDescription.setSeriesName(sequenceName);
String number = attributes.getValue("number");
myDescription.setNumberInSeries((number != null) ? Integer.parseInt(number) : 0);
name.trim();
if (name.length() != 0) {
String index = attributes.getValue("number");
myDescription.setSeriesInfo(name, (index != null) ? Integer.parseInt(index) : 0);
}
}
}
break;
@ -129,22 +127,21 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
break;
case FB2Tag.BOOK_TITLE:
if (myReadState == READ_TITLE) {
myDescription.setTitle(myBuffer.toString().trim());
myReadState = READ_SOMETHING;
}
break;
case FB2Tag.GENRE:
if (myReadState == READ_GENRE) {
final String genre = myGenreBuffer.toString().trim();
myGenreBuffer.delete(0, myGenreBuffer.length());
final String genre = myBuffer.toString().trim();
if (genre.length() > 0) {
final ArrayList tags = FB2TagManager.humanReadableTags(genre);
final ArrayList<Tag> tags = FB2TagManager.humanReadableTags(genre);
if (tags != null) {
final int len = tags.size();
for (int i = 0; i < len; ++i) {
myDescription.addTag((String)tags.get(i), false);
for (Tag t : tags) {
myDescription.addTag(t);
}
} else {
myDescription.addTag(genre, true);
myDescription.addTag(genre);
}
}
myReadState = READ_SOMETHING;
@ -173,6 +170,7 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
break;
case FB2Tag.LANG:
if (myReadState == READ_LANGUAGE) {
myDescription.setLanguage(myBuffer.toString().trim());
myReadState = READ_SOMETHING;
}
break;
@ -194,17 +192,12 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
default:
break;
}
myBuffer.delete(0, myBuffer.length());
return false;
}
public void characterDataHandler(char[] data, int start, int length) {
switch (myReadState) {
case READ_TITLE:
myDescription.setTitle(myDescription.getTitle() + new String(data, start, length));
break;
case READ_LANGUAGE:
myDescription.setLanguage(myDescription.getLanguage() + new String(data, start, length));
break;
case READ_AUTHOR_NAME_0:
myAuthorNames[0] += new String(data, start, length);
break;
@ -214,8 +207,10 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
case READ_AUTHOR_NAME_2:
myAuthorNames[2] += new String(data, start, length);
break;
case READ_TITLE:
case READ_LANGUAGE:
case READ_GENRE:
myGenreBuffer.append(data, start, length);
myBuffer.append(data, start, length);
break;
}
}

View file

@ -20,7 +20,7 @@
package org.geometerplus.fbreader.formats.fb2;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;

View file

@ -25,16 +25,18 @@ import org.geometerplus.zlibrary.core.util.*;
import org.geometerplus.zlibrary.core.library.ZLibrary;
import org.geometerplus.zlibrary.core.xml.*;
abstract class FB2TagManager {
private static final HashMap ourMap = new HashMap();
import org.geometerplus.fbreader.collection.Tag;
static ArrayList humanReadableTags(String id) {
abstract class FB2TagManager {
private static final HashMap<String,ArrayList<Tag>> ourMap = new HashMap<String,ArrayList<Tag>>();
static ArrayList<Tag> humanReadableTags(String id) {
if (ourMap.isEmpty()) {
new FB2TagInfoReader().read(
ZLibrary.JAR_DATA_PREFIX + "data/formats/fb2/fb2genres.xml"
);
}
return (ArrayList)ourMap.get(id);
return ourMap.get(id);
}
private FB2TagManager() {
@ -42,9 +44,9 @@ abstract class FB2TagManager {
private static class FB2TagInfoReader extends ZLXMLReaderAdapter {
private final String myLanguage;
private String myCategoryName;
private String mySubCategoryName;
private final ArrayList myGenreIds = new ArrayList();
private Tag myCategoryTag;
private Tag mySubCategoryTag;
private final ArrayList<String> myGenreIds = new ArrayList<String>();
FB2TagInfoReader() {
final String language = Locale.getDefault().getLanguage();
@ -59,17 +61,11 @@ abstract class FB2TagManager {
}
} else if (tag == "root-descr") {
if (myLanguage == attributes.getValue("lang")) {
final String name = attributes.getValue("genre-title");
if (name != null) {
myCategoryName = name.trim();
}
myCategoryTag = Tag.getTag(null, attributes.getValue("genre-title"));
}
} else if (tag == "genre-descr") {
if (myLanguage == attributes.getValue("lang")) {
final String name = attributes.getValue("title");
if (name != null) {
mySubCategoryName = name.trim();
}
mySubCategoryTag = Tag.getTag(myCategoryTag, attributes.getValue("title"));
}
}
return false;
@ -77,24 +73,21 @@ abstract class FB2TagManager {
public boolean endElementHandler(String tag) {
if (tag == "genre") {
myCategoryName = null;
mySubCategoryName = null;
myCategoryTag = null;
mySubCategoryTag = null;
myGenreIds.clear();
} else if (tag == "subgenre") {
if ((myCategoryName != null) && (mySubCategoryName != null)) {
final String fullTagName = myCategoryName + '/' + mySubCategoryName;
final int len = myGenreIds.size();
for (int i = 0; i < len; ++i) {
final Object id = myGenreIds.get(i);
ArrayList list = (ArrayList)ourMap.get(id);
if (mySubCategoryTag != null) {
for (String id : myGenreIds) {
ArrayList<Tag> list = ourMap.get(id);
if (list == null) {
list = new ArrayList();
list = new ArrayList<Tag>();
ourMap.put(id, list);
}
list.add(fullTagName);
list.add(mySubCategoryTag);
}
}
mySubCategoryName = null;
mySubCategoryTag = null;
myGenreIds.clear();
}
return false;

View file

@ -19,21 +19,19 @@
package org.geometerplus.fbreader.formats.html;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessor;
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessorFactory;
import org.geometerplus.zlibrary.core.xml.ZLXMLReaderAdapter;
public class HtmlDescriptionReader extends ZLXMLReaderAdapter {
private WritableBookDescription myDescription;
private final BookDescription myDescription;
private boolean myReadTitle;
public HtmlDescriptionReader(BookDescription description) {
myDescription = new WritableBookDescription(description);
myDescription = description;
myDescription.setTitle("");
}

View file

@ -20,8 +20,7 @@
package org.geometerplus.fbreader.formats.html;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.fbreader.formats.fb2.FB2DescriptionReader;
import org.geometerplus.fbreader.formats.fb2.FB2Reader;

View file

@ -22,11 +22,11 @@ package org.geometerplus.fbreader.formats.oeb;
import java.util.*;
import org.geometerplus.zlibrary.core.xml.*;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.constants.XMLNamespace;
class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
private final BookDescription.WritableBookDescription myDescription;
private final BookDescription myDescription;
private String myDCMetadataTag = "dc-metadata";
private String myMetadataTag = "metadata";
@ -36,14 +36,13 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
private String mySubjectTag;
private String myLanguageTag;
private final ArrayList myAuthorList = new ArrayList();
private final ArrayList myAuthorList2 = new ArrayList();
private final ArrayList<String> myAuthorList = new ArrayList<String>();
private final ArrayList<String> myAuthorList2 = new ArrayList<String>();
OEBDescriptionReader(BookDescription description) {
myDescription = new BookDescription.WritableBookDescription(description);
myDescription.clearAuthor();
myDescription.setTitle("");
myDescription.removeAllTags();
myDescription = description;
myDescription.setTitle(null);
myDescription.setLanguage(null);
}
boolean readDescription(String fileName) {
@ -56,10 +55,15 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
return false;
}
final ArrayList authors = myAuthorList.isEmpty() ? myAuthorList2 : myAuthorList;
final int len = authors.size();
for (int i = 0; i < len; ++i) {
myDescription.addAuthor((String)authors.get(i));
final ArrayList<String> authors = myAuthorList.isEmpty() ? myAuthorList2 : myAuthorList;
for (String a : authors) {
final int index = a.indexOf(',');
if (index >= 0) {
a = a.substring(index + 1).trim() + ' ' + a.substring(0, index).trim();
} else {
a = a.trim();
}
myDescription.addAuthor(a);
}
return true;
@ -158,7 +162,7 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
myAuthorList2.add(bufferContent);
break;
case READ_SUBJECT:
myDescription.addTag(bufferContent, true);
myDescription.addTag(bufferContent);
break;
case READ_LANGUAGE:
{

View file

@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.oeb;
import java.util.ArrayList;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.zlibrary.core.filesystem.*;
@ -61,7 +61,6 @@ public class OEBPlugin extends FormatPlugin {
public boolean readDescription(String path, BookDescription description) {
path = getOpfFileName(path);
System.err.println("path = " + path);
if (path == null) {
return false;
}

View file

@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.pdb;
import java.io.IOException;
import java.io.InputStream;
import org.geometerplus.fbreader.description.BookDescriptionUtil;
import org.geometerplus.fbreader.collection.BookDescriptionUtil;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.fbreader.formats.plucker.PluckerTextStream;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;

View file

@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.plucker;
import java.io.IOException;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.description.BookDescription;
import org.geometerplus.fbreader.collection.BookDescription;
import org.geometerplus.fbreader.formats.pdb.PdbPlugin;
import org.geometerplus.fbreader.formats.pdb.PdbStream;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;

View file

@ -127,7 +127,6 @@ public class KeyBindingsPage {
// dialogs
addAction(ActionCode.SHOW_OPTIONS);
addAction(ActionCode.SHOW_BOOK_INFO);
// quit
addAction(ActionCode.CANCEL);

View file

@ -401,7 +401,6 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
public synchronized void paint() {
//android.os.Debug.startMethodTracing("/tmp/paint");
myTextElementMap.clear();
myTreeNodeMap.clear();
@ -445,7 +444,6 @@ public abstract class ZLTextViewImpl extends ZLTextView {
for (int i = 0; i < lineInfosSize; ++i) {
drawTextLine(context, lineInfos.getInfo(i), labels[i], labels[i + 1]);
}
//android.os.Debug.stopMethodTracing();
}
private int sizeOfTextBeforeCursor(ZLTextWordCursor wordCursor) {