From 68167fe2bc455c6bd563929b01867fceefc68c39 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Mon, 6 Apr 2009 15:57:40 +0000 Subject: [PATCH] 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 --- .../android/res/layout/library_tree_item.xml | 4 +- .../android/fbreader/FBReader.java | 4 +- .../android/fbreader/SQLiteBooksDatabase.java | 368 +++++++++++++++ .../android/fbreader/TOCActivity.java | 91 +++- .../android/fbreader/ZLTreeAdapter.java | 75 ++-- .../fbreader/bookmodel/BookModel.java | 4 +- .../fbreader/bookmodel/BookReader.java | 19 +- .../{ContentsTree.java => TOCTree.java} | 43 +- .../fbreader/booksdb/BookInfo.java | 167 ------- .../fbreader/booksdb/BooksDatabase.java | 96 ---- .../{description => collection}/Author.java | 10 +- .../fbreader/collection/AuthorTree.java | 7 +- .../fbreader/collection/BookCollection.java | 82 ++-- .../fbreader/collection/BookDescription.java | 257 +++++++++++ .../BookDescriptionUtil.java | 38 +- .../fbreader/collection/BookInSeriesTree.java | 7 +- .../fbreader/collection/BookTree.java | 2 - .../fbreader/collection/BooksDatabase.java | 46 ++ .../fbreader/collection/CollectionTree.java | 4 +- .../fbreader/collection/RecentBooks.java | 1 - .../collection/SeriesInfo.java} | 32 +- .../fbreader/collection/SeriesTree.java | 2 - .../geometerplus/fbreader/collection/Tag.java | 65 +++ .../fbreader/collection/TagTree.java | 8 +- .../fbreader/description/BookDescription.java | 423 ------------------ .../fbreader/fbreader/ActionCode.java | 1 - .../fbreader/fbreader/BookInfoDialog.java | 215 --------- .../fbreader/fbreader/FBReader.java | 8 +- .../fbreader/ShowBookInfoDialogAction.java | 43 -- .../fbreader/fbreader/ShowHelpAction.java | 2 +- .../fbreader/fbreader/ShowTOCAction.java | 2 +- .../fbreader/formats/FormatPlugin.java | 15 +- .../formats/fb2/FB2DescriptionReader.java | 53 +-- .../fbreader/formats/fb2/FB2Plugin.java | 2 +- .../fbreader/formats/fb2/FB2TagManager.java | 45 +- .../formats/html/HtmlDescriptionReader.java | 8 +- .../fbreader/formats/html/HtmlPlugin.java | 3 +- .../formats/oeb/OEBDescriptionReader.java | 30 +- .../fbreader/formats/oeb/OEBPlugin.java | 3 +- .../fbreader/formats/pdb/PdbPlugin.java | 2 +- .../formats/plucker/PluckerPlugin.java | 2 +- .../optionsDialog/KeyBindingsPage.java | 1 - .../text/view/impl/ZLTextViewImpl.java | 2 - 43 files changed, 1055 insertions(+), 1237 deletions(-) create mode 100644 platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java rename src/org/geometerplus/fbreader/bookmodel/{ContentsTree.java => TOCTree.java} (60%) delete mode 100644 src/org/geometerplus/fbreader/booksdb/BookInfo.java delete mode 100644 src/org/geometerplus/fbreader/booksdb/BooksDatabase.java rename src/org/geometerplus/fbreader/{description => collection}/Author.java (90%) create mode 100644 src/org/geometerplus/fbreader/collection/BookDescription.java rename src/org/geometerplus/fbreader/{description => collection}/BookDescriptionUtil.java (78%) create mode 100644 src/org/geometerplus/fbreader/collection/BooksDatabase.java rename src/org/geometerplus/{zlibrary/core/tree/ZLStringTree.java => fbreader/collection/SeriesInfo.java} (60%) create mode 100644 src/org/geometerplus/fbreader/collection/Tag.java delete mode 100644 src/org/geometerplus/fbreader/description/BookDescription.java delete mode 100644 src/org/geometerplus/fbreader/fbreader/BookInfoDialog.java delete mode 100644 src/org/geometerplus/fbreader/fbreader/ShowBookInfoDialogAction.java diff --git a/platform/android/res/layout/library_tree_item.xml b/platform/android/res/layout/library_tree_item.xml index c960f44b4..76a7d92eb 100644 --- a/platform/android/res/layout/library_tree_item.xml +++ b/platform/android/res/layout/library_tree_item.xml @@ -1,5 +1,5 @@ - - + diff --git a/platform/android/src/org/geometerplus/android/fbreader/FBReader.java b/platform/android/src/org/geometerplus/android/fbreader/FBReader.java index 7c475a7da..ad212fb13 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/FBReader.java +++ b/platform/android/src/org/geometerplus/android/fbreader/FBReader.java @@ -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; } } diff --git a/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java b/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java new file mode 100644 index 000000000..34521172c --- /dev/null +++ b/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2009 Geometer Plus + * + * 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 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 list = new ArrayList(cursor.getCount()); + do { + list.add(new Author(cursor.getString(0), cursor.getString(1))); + } while (cursor.moveToNext()); + cursor.close(); + return list; + } + + private HashMap myIdByTag = new HashMap(); + private HashMap myTagById = new HashMap(); + + 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 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 list = new ArrayList(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) { + } + } +} diff --git a/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java b/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java index 3cee90d35..316a5e825 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java +++ b/platform/android/src/org/geometerplus/android/fbreader/TOCActivity.java @@ -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; } } diff --git a/platform/android/src/org/geometerplus/android/fbreader/ZLTreeAdapter.java b/platform/android/src/org/geometerplus/android/fbreader/ZLTreeAdapter.java index 9aea43194..35820a9f4 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/ZLTreeAdapter.java +++ b/platform/android/src/org/geometerplus/android/fbreader/ZLTreeAdapter.java @@ -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); diff --git a/src/org/geometerplus/fbreader/bookmodel/BookModel.java b/src/org/geometerplus/fbreader/bookmodel/BookModel.java index 04e994732..e087192fe 100644 --- a/src/org/geometerplus/fbreader/bookmodel/BookModel.java +++ b/src/org/geometerplus/fbreader/bookmodel/BookModel.java @@ -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 myFootnotes = new HashMap(); private final HashMap myInternalHyperlinks = new HashMap(); diff --git a/src/org/geometerplus/fbreader/bookmodel/BookReader.java b/src/org/geometerplus/fbreader/bookmodel/BookReader.java index b9ae4b95a..c8f71630b 100644 --- a/src/org/geometerplus/fbreader/bookmodel/BookReader.java +++ b/src/org/geometerplus/fbreader/bookmodel/BookReader.java @@ -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 ); } } diff --git a/src/org/geometerplus/fbreader/bookmodel/ContentsTree.java b/src/org/geometerplus/fbreader/bookmodel/TOCTree.java similarity index 60% rename from src/org/geometerplus/fbreader/bookmodel/ContentsTree.java rename to src/org/geometerplus/fbreader/bookmodel/TOCTree.java index 8d40da3ad..786d7499e 100644 --- a/src/org/geometerplus/fbreader/bookmodel/ContentsTree.java +++ b/src/org/geometerplus/fbreader/bookmodel/TOCTree.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2009 Geometer Plus + * Copyright (C) 2009 Geometer Plus * * 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 myReferenceByTree = new HashMap(); - - public Reference getReference(ZLStringTree tree) { - return myReferenceByTree.get(tree); +public class TOCTree extends ZLTree { + private String myText; + private Reference myReference; + + protected TOCTree() { + super(); + } + + private TOCTree(TOCTree parent) { + super(parent); + } + + public final String getText() { + return myText; + } + + public final void setText(String text) { + myText = text; } - public void setReference(ZLStringTree tree, ZLTextModel model, int reference) { - myReferenceByTree.put(tree, new Reference(reference, model)); + 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 { diff --git a/src/org/geometerplus/fbreader/booksdb/BookInfo.java b/src/org/geometerplus/fbreader/booksdb/BookInfo.java deleted file mode 100644 index 3e4a104c8..000000000 --- a/src/org/geometerplus/fbreader/booksdb/BookInfo.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2009 Geometer Plus - * - * 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; - } - } -} diff --git a/src/org/geometerplus/fbreader/booksdb/BooksDatabase.java b/src/org/geometerplus/fbreader/booksdb/BooksDatabase.java deleted file mode 100644 index b121d65a8..000000000 --- a/src/org/geometerplus/fbreader/booksdb/BooksDatabase.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2009 Geometer Plus - * - * 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); - } - } -} diff --git a/src/org/geometerplus/fbreader/description/Author.java b/src/org/geometerplus/fbreader/collection/Author.java similarity index 90% rename from src/org/geometerplus/fbreader/description/Author.java rename to src/org/geometerplus/fbreader/collection/Author.java index 9cab0c5a3..3e9c19610 100644 --- a/src/org/geometerplus/fbreader/description/Author.java +++ b/src/org/geometerplus/fbreader/collection/Author.java @@ -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(); } diff --git a/src/org/geometerplus/fbreader/collection/AuthorTree.java b/src/org/geometerplus/fbreader/collection/AuthorTree.java index 8ad3894ea..1834074b3 100644 --- a/src/org/geometerplus/fbreader/collection/AuthorTree.java +++ b/src/org/geometerplus/fbreader/collection/AuthorTree.java @@ -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; } } diff --git a/src/org/geometerplus/fbreader/collection/BookCollection.java b/src/org/geometerplus/fbreader/collection/BookCollection.java index 5517c852e..26b4d5f27 100644 --- a/src/org/geometerplus/fbreader/collection/BookCollection.java +++ b/src/org/geometerplus/fbreader/collection/BookCollection.java @@ -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 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 tagTreeMap = new HashMap(); + final HashMap tagTreeMap = new HashMap(); final HashMap authorTreeMap = new HashMap(); final HashMap seriesTreeMap = new HashMap(); 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 authors = description.authors(); + if (authors.isEmpty()) { + authors = (List)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 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 tags = description.tags(); + if (tags.isEmpty()) { + tags = (List)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(); } diff --git a/src/org/geometerplus/fbreader/collection/BookDescription.java b/src/org/geometerplus/fbreader/collection/BookDescription.java new file mode 100644 index 000000000..fcab3f7ca --- /dev/null +++ b/src/org/geometerplus/fbreader/collection/BookDescription.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2007-2009 Geometer Plus + * + * 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 myAuthors; + private ArrayList myTags; + private SeriesInfo mySeriesInfo; + + private boolean myIsSaved; + private boolean myIsChanged; + + private final static HashMap ourDescriptions = new HashMap(); + + 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 authors() { + return (myAuthors != null) ? Collections.unmodifiableList(myAuthors) : Collections.emptyList(); + } + + private void addAuthor(Author author) { + if (author == null) { + return; + } + if (myAuthors == null) { + myAuthors = new ArrayList(); + 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 tags() { + return (myTags != null) ? Collections.unmodifiableList(myTags) : Collections.emptyList(); + } + + public void addTag(Tag tag) { + if (tag != null) { + if (myTags == null) { + myTags = new ArrayList(); + } + 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); + } + +} diff --git a/src/org/geometerplus/fbreader/description/BookDescriptionUtil.java b/src/org/geometerplus/fbreader/collection/BookDescriptionUtil.java similarity index 78% rename from src/org/geometerplus/fbreader/description/BookDescriptionUtil.java rename to src/org/geometerplus/fbreader/collection/BookDescriptionUtil.java index ba48eef10..8122ea646 100644 --- a/src/org/geometerplus/fbreader/description/BookDescriptionUtil.java +++ b/src/org/geometerplus/fbreader/collection/BookDescriptionUtil.java @@ -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,9 +37,8 @@ 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) { new ZLIntegerOption(file.getPath(), SIZE, -1).setValue((int)file.size()); } @@ -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(); - } - } } diff --git a/src/org/geometerplus/fbreader/collection/BookInSeriesTree.java b/src/org/geometerplus/fbreader/collection/BookInSeriesTree.java index 294e7c78c..08c6c7570 100644 --- a/src/org/geometerplus/fbreader/collection/BookInSeriesTree.java +++ b/src/org/geometerplus/fbreader/collection/BookInSeriesTree.java @@ -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); diff --git a/src/org/geometerplus/fbreader/collection/BookTree.java b/src/org/geometerplus/fbreader/collection/BookTree.java index f4c0c97e5..df8451856 100644 --- a/src/org/geometerplus/fbreader/collection/BookTree.java +++ b/src/org/geometerplus/fbreader/collection/BookTree.java @@ -19,8 +19,6 @@ package org.geometerplus.fbreader.collection; -import org.geometerplus.fbreader.description.BookDescription; - public class BookTree extends CollectionTree { public final BookDescription Description; diff --git a/src/org/geometerplus/fbreader/collection/BooksDatabase.java b/src/org/geometerplus/fbreader/collection/BooksDatabase.java new file mode 100644 index 000000000..f5cbe699c --- /dev/null +++ b/src/org/geometerplus/fbreader/collection/BooksDatabase.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Geometer Plus + * + * 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 loadAuthors(long bookId); + public abstract ArrayList 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); +} diff --git a/src/org/geometerplus/fbreader/collection/CollectionTree.java b/src/org/geometerplus/fbreader/collection/CollectionTree.java index f18dfb886..524a9026f 100644 --- a/src/org/geometerplus/fbreader/collection/CollectionTree.java +++ b/src/org/geometerplus/fbreader/collection/CollectionTree.java @@ -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 implements Comparable { protected CollectionTree() { @@ -35,7 +33,7 @@ public abstract class CollectionTree extends ZLTree implements C super(parent); } - TagTree createTagSubTree(String tag) { + TagTree createTagSubTree(Tag tag) { TagTree tree = new TagTree(this, tag); addSubTree(tree); return tree; diff --git a/src/org/geometerplus/fbreader/collection/RecentBooks.java b/src/org/geometerplus/fbreader/collection/RecentBooks.java index 5180f371e..9ff21132e 100644 --- a/src/org/geometerplus/fbreader/collection/RecentBooks.java +++ b/src/org/geometerplus/fbreader/collection/RecentBooks.java @@ -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 { diff --git a/src/org/geometerplus/zlibrary/core/tree/ZLStringTree.java b/src/org/geometerplus/fbreader/collection/SeriesInfo.java similarity index 60% rename from src/org/geometerplus/zlibrary/core/tree/ZLStringTree.java rename to src/org/geometerplus/fbreader/collection/SeriesInfo.java index 42164bc2e..ba3868201 100644 --- a/src/org/geometerplus/zlibrary/core/tree/ZLStringTree.java +++ b/src/org/geometerplus/fbreader/collection/SeriesInfo.java @@ -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 { - 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; } } diff --git a/src/org/geometerplus/fbreader/collection/SeriesTree.java b/src/org/geometerplus/fbreader/collection/SeriesTree.java index a94452408..e88cf4462 100644 --- a/src/org/geometerplus/fbreader/collection/SeriesTree.java +++ b/src/org/geometerplus/fbreader/collection/SeriesTree.java @@ -19,8 +19,6 @@ package org.geometerplus.fbreader.collection; -import org.geometerplus.fbreader.description.BookDescription; - final class SeriesTree extends CollectionTree { private final String mySeries; diff --git a/src/org/geometerplus/fbreader/collection/Tag.java b/src/org/geometerplus/fbreader/collection/Tag.java new file mode 100644 index 000000000..f11c82cc3 --- /dev/null +++ b/src/org/geometerplus/fbreader/collection/Tag.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Geometer Plus + * + * 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 ourTagSet = new HashMap(); + + 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(); + } +} diff --git a/src/org/geometerplus/fbreader/collection/TagTree.java b/src/org/geometerplus/fbreader/collection/TagTree.java index 443373e85..3ffe8c31f 100644 --- a/src/org/geometerplus/fbreader/collection/TagTree.java +++ b/src/org/geometerplus/fbreader/collection/TagTree.java @@ -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; } } diff --git a/src/org/geometerplus/fbreader/description/BookDescription.java b/src/org/geometerplus/fbreader/description/BookDescription.java deleted file mode 100644 index 6f23a5b2b..000000000 --- a/src/org/geometerplus/fbreader/description/BookDescription.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2007-2009 Geometer Plus - * - * 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 myAuthors = new TreeSet(); - 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 myTags = new ArrayList(); - - 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 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 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 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 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 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(); - } - }; -} diff --git a/src/org/geometerplus/fbreader/fbreader/ActionCode.java b/src/org/geometerplus/fbreader/fbreader/ActionCode.java index c4dad687c..54505194e 100644 --- a/src/org/geometerplus/fbreader/fbreader/ActionCode.java +++ b/src/org/geometerplus/fbreader/fbreader/ActionCode.java @@ -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"; diff --git a/src/org/geometerplus/fbreader/fbreader/BookInfoDialog.java b/src/org/geometerplus/fbreader/fbreader/BookInfoDialog.java deleted file mode 100644 index ff95a69ca..000000000 --- a/src/org/geometerplus/fbreader/fbreader/BookInfoDialog.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2007-2009 Geometer Plus - * - * 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/**/ 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 authors = myCollection.authors(); - if (index < authors.size()) { - myCurrentAuthor = new ArrayList(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); - } - } -} diff --git a/src/org/geometerplus/fbreader/fbreader/FBReader.java b/src/org/geometerplus/fbreader/fbreader/FBReader.java index e3337c5de..a1e9e03cb 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReader.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReader.java @@ -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)); } } diff --git a/src/org/geometerplus/fbreader/fbreader/ShowBookInfoDialogAction.java b/src/org/geometerplus/fbreader/fbreader/ShowBookInfoDialogAction.java deleted file mode 100644 index 77c1c99a7..000000000 --- a/src/org/geometerplus/fbreader/fbreader/ShowBookInfoDialogAction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2007-2009 Geometer Plus - * - * 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(); - } -} diff --git a/src/org/geometerplus/fbreader/fbreader/ShowHelpAction.java b/src/org/geometerplus/fbreader/fbreader/ShowHelpAction.java index ab89e31bd..7184b4324 100644 --- a/src/org/geometerplus/fbreader/fbreader/ShowHelpAction.java +++ b/src/org/geometerplus/fbreader/fbreader/ShowHelpAction.java @@ -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) { diff --git a/src/org/geometerplus/fbreader/fbreader/ShowTOCAction.java b/src/org/geometerplus/fbreader/fbreader/ShowTOCAction.java index 6eb3858f8..80fc62829 100644 --- a/src/org/geometerplus/fbreader/fbreader/ShowTOCAction.java +++ b/src/org/geometerplus/fbreader/fbreader/ShowTOCAction.java @@ -29,7 +29,7 @@ class ShowTOCAction extends FBAction { } public boolean isVisible() { - return Reader.Model.ContentsTree.hasChildren(); + return Reader.Model.TOCTree.hasChildren(); } public void run() { diff --git a/src/org/geometerplus/fbreader/formats/FormatPlugin.java b/src/org/geometerplus/fbreader/formats/FormatPlugin.java index 0cd72be35..108f34a93 100644 --- a/src/org/geometerplus/fbreader/formats/FormatPlugin.java +++ b/src/org/geometerplus/fbreader/formats/FormatPlugin.java @@ -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"); }*/ /*} diff --git a/src/org/geometerplus/fbreader/formats/fb2/FB2DescriptionReader.java b/src/org/geometerplus/fbreader/formats/fb2/FB2DescriptionReader.java index 337a73658..40cf8d1b3 100644 --- a/src/org/geometerplus/fbreader/formats/fb2/FB2DescriptionReader.java +++ b/src/org/geometerplus/fbreader/formats/fb2/FB2DescriptionReader.java @@ -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 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; } } diff --git a/src/org/geometerplus/fbreader/formats/fb2/FB2Plugin.java b/src/org/geometerplus/fbreader/formats/fb2/FB2Plugin.java index 74a70c40f..35d20dab6 100644 --- a/src/org/geometerplus/fbreader/formats/fb2/FB2Plugin.java +++ b/src/org/geometerplus/fbreader/formats/fb2/FB2Plugin.java @@ -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; diff --git a/src/org/geometerplus/fbreader/formats/fb2/FB2TagManager.java b/src/org/geometerplus/fbreader/formats/fb2/FB2TagManager.java index 1914941ad..754e7a58c 100644 --- a/src/org/geometerplus/fbreader/formats/fb2/FB2TagManager.java +++ b/src/org/geometerplus/fbreader/formats/fb2/FB2TagManager.java @@ -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> ourMap = new HashMap>(); + + static ArrayList 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 myGenreIds = new ArrayList(); 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 list = ourMap.get(id); if (list == null) { - list = new ArrayList(); + list = new ArrayList(); ourMap.put(id, list); } - list.add(fullTagName); + list.add(mySubCategoryTag); } } - mySubCategoryName = null; + mySubCategoryTag = null; myGenreIds.clear(); } return false; diff --git a/src/org/geometerplus/fbreader/formats/html/HtmlDescriptionReader.java b/src/org/geometerplus/fbreader/formats/html/HtmlDescriptionReader.java index 8f2a94d16..42e7f7980 100644 --- a/src/org/geometerplus/fbreader/formats/html/HtmlDescriptionReader.java +++ b/src/org/geometerplus/fbreader/formats/html/HtmlDescriptionReader.java @@ -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(""); } diff --git a/src/org/geometerplus/fbreader/formats/html/HtmlPlugin.java b/src/org/geometerplus/fbreader/formats/html/HtmlPlugin.java index d89170741..eb9a26c6c 100644 --- a/src/org/geometerplus/fbreader/formats/html/HtmlPlugin.java +++ b/src/org/geometerplus/fbreader/formats/html/HtmlPlugin.java @@ -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; diff --git a/src/org/geometerplus/fbreader/formats/oeb/OEBDescriptionReader.java b/src/org/geometerplus/fbreader/formats/oeb/OEBDescriptionReader.java index c53861310..ebfaac0be 100644 --- a/src/org/geometerplus/fbreader/formats/oeb/OEBDescriptionReader.java +++ b/src/org/geometerplus/fbreader/formats/oeb/OEBDescriptionReader.java @@ -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 myAuthorList = new ArrayList(); + private final ArrayList myAuthorList2 = new ArrayList(); 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 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: { diff --git a/src/org/geometerplus/fbreader/formats/oeb/OEBPlugin.java b/src/org/geometerplus/fbreader/formats/oeb/OEBPlugin.java index d5f06afb4..12e23c95d 100644 --- a/src/org/geometerplus/fbreader/formats/oeb/OEBPlugin.java +++ b/src/org/geometerplus/fbreader/formats/oeb/OEBPlugin.java @@ -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; } diff --git a/src/org/geometerplus/fbreader/formats/pdb/PdbPlugin.java b/src/org/geometerplus/fbreader/formats/pdb/PdbPlugin.java index 7f47168ba..332df47ab 100644 --- a/src/org/geometerplus/fbreader/formats/pdb/PdbPlugin.java +++ b/src/org/geometerplus/fbreader/formats/pdb/PdbPlugin.java @@ -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; diff --git a/src/org/geometerplus/fbreader/formats/plucker/PluckerPlugin.java b/src/org/geometerplus/fbreader/formats/plucker/PluckerPlugin.java index eb6533cf4..190d27d72 100644 --- a/src/org/geometerplus/fbreader/formats/plucker/PluckerPlugin.java +++ b/src/org/geometerplus/fbreader/formats/plucker/PluckerPlugin.java @@ -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; diff --git a/src/org/geometerplus/fbreader/optionsDialog/KeyBindingsPage.java b/src/org/geometerplus/fbreader/optionsDialog/KeyBindingsPage.java index 22f69f608..36b8a5900 100644 --- a/src/org/geometerplus/fbreader/optionsDialog/KeyBindingsPage.java +++ b/src/org/geometerplus/fbreader/optionsDialog/KeyBindingsPage.java @@ -127,7 +127,6 @@ public class KeyBindingsPage { // dialogs addAction(ActionCode.SHOW_OPTIONS); - addAction(ActionCode.SHOW_BOOK_INFO); // quit addAction(ActionCode.CANCEL); diff --git a/src/org/geometerplus/zlibrary/text/view/impl/ZLTextViewImpl.java b/src/org/geometerplus/zlibrary/text/view/impl/ZLTextViewImpl.java index ded183bc8..d288dd62d 100644 --- a/src/org/geometerplus/zlibrary/text/view/impl/ZLTextViewImpl.java +++ b/src/org/geometerplus/zlibrary/text/view/impl/ZLTextViewImpl.java @@ -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) {