mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 10:49:24 +02:00
added context menu for TOC
selected current item in TOC implemented tag tree in library implemented full library database git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@909 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
fad63e3659
commit
68167fe2bc
43 changed files with 1055 additions and 1237 deletions
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.geometerplus.android.fbreader.TOCTreeItemView xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
@ -39,4 +39,4 @@
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</org.geometerplus.android.fbreader.TOCTreeItemView>
|
</LinearLayout>
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.geometerplus.zlibrary.ui.android.library.ZLAndroidActivity;
|
||||||
public class FBReader extends ZLAndroidActivity {
|
public class FBReader extends ZLAndroidActivity {
|
||||||
protected ZLApplication createApplication(String fileName) {
|
protected ZLApplication createApplication(String fileName) {
|
||||||
String[] args = (fileName != null) ? new String[] { fileName } : new String[0];
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.android.fbreader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteStatement;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.collection.*;
|
||||||
|
|
||||||
|
final class SQLiteBooksDatabase extends BooksDatabase {
|
||||||
|
private final SQLiteDatabase myDatabase;
|
||||||
|
|
||||||
|
SQLiteBooksDatabase() {
|
||||||
|
myDatabase = ZLAndroidApplication.Instance().openOrCreateDatabase("books.db", Context.MODE_PRIVATE, null);
|
||||||
|
if (myDatabase.getVersion() == 0) {
|
||||||
|
createTables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executeAsATransaction(Runnable actions) {
|
||||||
|
myDatabase.beginTransaction();
|
||||||
|
try {
|
||||||
|
actions.run();
|
||||||
|
myDatabase.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
myDatabase.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTables() {
|
||||||
|
myDatabase.beginTransaction();
|
||||||
|
/*
|
||||||
|
myDatabase.execSQL("DROP TABLE Books");
|
||||||
|
myDatabase.execSQL("DROP TABLE Authors");
|
||||||
|
myDatabase.execSQL("DROP TABLE Series");
|
||||||
|
myDatabase.execSQL("DROP TABLE Tags");
|
||||||
|
myDatabase.execSQL("DROP TABLE BookAuthor");
|
||||||
|
myDatabase.execSQL("DROP TABLE BookSeries");
|
||||||
|
myDatabase.execSQL("DROP TABLE BookTag");
|
||||||
|
*/
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE Books(" +
|
||||||
|
"book_id INTEGER PRIMARY KEY," +
|
||||||
|
"encoding TEXT," +
|
||||||
|
"language TEXT," +
|
||||||
|
"title TEXT NOT NULL," +
|
||||||
|
"file_name TEXT UNIQUE NOT NULL)");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE Authors(" +
|
||||||
|
"author_id INTEGER PRIMARY KEY," +
|
||||||
|
"name TEXT NOT NULL," +
|
||||||
|
"sort_key TEXT NOT NULL," +
|
||||||
|
"CONSTRAINT Authors_Unique UNIQUE (name, sort_key))");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE BookAuthor(" +
|
||||||
|
"author_id INTEGER NOT NULL REFERENCES Authors(author_id)," +
|
||||||
|
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
|
||||||
|
"author_index INTEGER NOT NULL," +
|
||||||
|
"CONSTRAINT BookAuthor_Unique0 UNIQUE (author_id, book_id)," +
|
||||||
|
"CONSTRAINT BookAuthor_Unique1 UNIQUE (book_id, author_index))");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE Series(" +
|
||||||
|
"series_id INTEGER PRIMARY KEY," +
|
||||||
|
"name TEXT UNIQUE NOT NULL)");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE BookSeries(" +
|
||||||
|
"series_id INTEGER NOT NULL REFERENCES Series(series_id)," +
|
||||||
|
"book_id INTEGER NOT NULL UNIQUE REFERENCES Books(book_id)," +
|
||||||
|
"book_index INTEGER)");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE Tags(" +
|
||||||
|
"tag_id INTEGER PRIMARY KEY," +
|
||||||
|
"name TEXT NOT NULL," +
|
||||||
|
"parent INTEGER REFERENCES Tags(tag_id)," +
|
||||||
|
"CONSTRAINT Tags_Unique UNIQUE (name, parent))");
|
||||||
|
myDatabase.execSQL(
|
||||||
|
"CREATE TABLE BookTag(" +
|
||||||
|
"tag_id INTEGER REFERENCES Tags(tag_id)," +
|
||||||
|
"book_id INTEGER REFERENCES Books(book_id)," +
|
||||||
|
"CONSTRAINT BookTag_Unique UNIQUE (tag_id, book_id))");
|
||||||
|
myDatabase.setTransactionSuccessful();
|
||||||
|
myDatabase.endTransaction();
|
||||||
|
|
||||||
|
myDatabase.setVersion(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void bindString(SQLiteStatement statement, int index, String value) {
|
||||||
|
if (value != null) {
|
||||||
|
statement.bindString(index, value);
|
||||||
|
} else {
|
||||||
|
statement.bindNull(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String BOOKS_TABLE = "Books";
|
||||||
|
private static final String[] BOOKS_COLUMNS = { "book_id", "encoding", "language", "title" };
|
||||||
|
private static final String FILE_NAME_CONDITION = "file_name = ?";
|
||||||
|
public long loadBook(BookDescription description) {
|
||||||
|
final Cursor cursor = myDatabase.query(
|
||||||
|
BOOKS_TABLE,
|
||||||
|
BOOKS_COLUMNS,
|
||||||
|
FILE_NAME_CONDITION, new String[] { description.FileName },
|
||||||
|
null, null, null, null
|
||||||
|
);
|
||||||
|
long id = -1;
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
id = cursor.getLong(0);
|
||||||
|
description.setEncoding(cursor.getString(1));
|
||||||
|
description.setLanguage(cursor.getString(2));
|
||||||
|
description.setTitle(cursor.getString(3));
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myUpdateBookInfoStatement;
|
||||||
|
public void updateBookInfo(long bookId, String encoding, String language, String title) {
|
||||||
|
if (myUpdateBookInfoStatement == null) {
|
||||||
|
myUpdateBookInfoStatement = myDatabase.compileStatement(
|
||||||
|
"UPDATE Books SET encoding = ? language = ? title = ? WHERE book_id = ?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bindString(myUpdateBookInfoStatement, 1, encoding);
|
||||||
|
bindString(myUpdateBookInfoStatement, 2, language);
|
||||||
|
myUpdateBookInfoStatement.bindString(3, title);
|
||||||
|
myUpdateBookInfoStatement.bindLong(4, bookId);
|
||||||
|
myUpdateBookInfoStatement.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myInsertBookInfoStatement;
|
||||||
|
public long insertBookInfo(String fileName, String encoding, String language, String title) {
|
||||||
|
if (myInsertBookInfoStatement == null) {
|
||||||
|
myInsertBookInfoStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO Books (encoding,language,title,file_name) VALUES (?,?,?,?)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bindString(myInsertBookInfoStatement, 1, encoding);
|
||||||
|
bindString(myInsertBookInfoStatement, 2, language);
|
||||||
|
myInsertBookInfoStatement.bindString(3, title);
|
||||||
|
myInsertBookInfoStatement.bindString(4, fileName);
|
||||||
|
return myInsertBookInfoStatement.executeInsert();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myGetAuthorIdStatement;
|
||||||
|
private SQLiteStatement myInsertAuthorStatement;
|
||||||
|
private SQLiteStatement myInsertBookAuthorStatement;
|
||||||
|
public void saveBookAuthorInfo(long bookId, long index, Author author) {
|
||||||
|
if (myGetAuthorIdStatement == null) {
|
||||||
|
myGetAuthorIdStatement = myDatabase.compileStatement(
|
||||||
|
"SELECT author_id FROM Authors WHERE name = ? AND sort_key = ?"
|
||||||
|
);
|
||||||
|
myInsertAuthorStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO Authors (name,sort_key) VALUES (?,?)"
|
||||||
|
);
|
||||||
|
myInsertBookAuthorStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT OR IGNORE INTO BookAuthor (book_id,author_id,author_index) VALUES (?,?,?)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
long authorId;
|
||||||
|
try {
|
||||||
|
myGetAuthorIdStatement.bindString(1, author.DisplayName);
|
||||||
|
myGetAuthorIdStatement.bindString(2, author.SortKey);
|
||||||
|
authorId = myGetAuthorIdStatement.simpleQueryForLong();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
myInsertAuthorStatement.bindString(1, author.DisplayName);
|
||||||
|
myInsertAuthorStatement.bindString(2, author.SortKey);
|
||||||
|
authorId = myInsertAuthorStatement.executeInsert();
|
||||||
|
}
|
||||||
|
myInsertBookAuthorStatement.bindLong(1, bookId);
|
||||||
|
myInsertBookAuthorStatement.bindLong(2, authorId);
|
||||||
|
myInsertBookAuthorStatement.bindLong(3, index);
|
||||||
|
myInsertBookAuthorStatement.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Author> loadAuthors(long bookId) {
|
||||||
|
final Cursor cursor = myDatabase.rawQuery("SELECT Authors.name,Authors.sort_key FROM BookAuthor INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id WHERE BookAuthor.book_id = ?", new String[] { "" + bookId });
|
||||||
|
if (!cursor.moveToNext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<Author> list = new ArrayList<Author>(cursor.getCount());
|
||||||
|
do {
|
||||||
|
list.add(new Author(cursor.getString(0), cursor.getString(1)));
|
||||||
|
} while (cursor.moveToNext());
|
||||||
|
cursor.close();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<Tag,Long> myIdByTag = new HashMap<Tag,Long>();
|
||||||
|
private HashMap<Long,Tag> myTagById = new HashMap<Long,Tag>();
|
||||||
|
|
||||||
|
private SQLiteStatement myGetTagIdStatement;
|
||||||
|
private SQLiteStatement myCreateTagIdStatement;
|
||||||
|
private long getTagId(Tag tag) {
|
||||||
|
if (myGetTagIdStatement == null) {
|
||||||
|
myGetTagIdStatement = myDatabase.compileStatement(
|
||||||
|
"SELECT tag_id FROM Tags WHERE parent = ? AND name = ?"
|
||||||
|
);
|
||||||
|
myCreateTagIdStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO Tags (parent,name) VALUES (?,?)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final Long id = myIdByTag.get(tag);
|
||||||
|
if (id != null) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tag.Parent != null) {
|
||||||
|
myGetTagIdStatement.bindLong(1, getTagId(tag.Parent));
|
||||||
|
} else {
|
||||||
|
myGetTagIdStatement.bindNull(1);
|
||||||
|
}
|
||||||
|
myGetTagIdStatement.bindString(2, tag.Name);
|
||||||
|
long id;
|
||||||
|
try {
|
||||||
|
id = myGetTagIdStatement.simpleQueryForLong();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
if (tag.Parent != null) {
|
||||||
|
myCreateTagIdStatement.bindLong(1, getTagId(tag.Parent));
|
||||||
|
} else {
|
||||||
|
myCreateTagIdStatement.bindNull(1);
|
||||||
|
}
|
||||||
|
myCreateTagIdStatement.bindString(2, tag.Name);
|
||||||
|
id = myCreateTagIdStatement.executeInsert();
|
||||||
|
}
|
||||||
|
myIdByTag.put(tag, id);
|
||||||
|
myTagById.put(id, tag);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myInsertBookTagStatement;
|
||||||
|
public void saveBookTagInfo(long bookId, Tag tag) {
|
||||||
|
if (myInsertBookTagStatement == null) {
|
||||||
|
myInsertBookTagStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO BookTag (book_id,tag_id) VALUES (?,?)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
myInsertBookTagStatement.bindLong(1, bookId);
|
||||||
|
myInsertBookTagStatement.bindLong(2, getTagId(tag));
|
||||||
|
myInsertBookTagStatement.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tag getTagById(long id) {
|
||||||
|
Tag tag = myTagById.get(id);
|
||||||
|
if (tag == null) {
|
||||||
|
final Cursor cursor = myDatabase.rawQuery("SELECT parent,name FROM Tags WHERE tag_id = ?", new String[] { "" + id });
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
final Tag parent = cursor.isNull(0) ? null : getTagById(cursor.getLong(0));
|
||||||
|
tag = Tag.getTag(parent, cursor.getString(1));
|
||||||
|
myIdByTag.put(tag, id);
|
||||||
|
myTagById.put(id, tag);
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Tag> loadTags(long bookId) {
|
||||||
|
final Cursor cursor = myDatabase.rawQuery("SELECT Tags.tag_id FROM BookTag INNER JOIN Tags ON Tags.tag_id = BookTag.tag_id WHERE BookTag.book_id = ?", new String[] { "" + bookId });
|
||||||
|
if (!cursor.moveToNext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<Tag> list = new ArrayList<Tag>(cursor.getCount());
|
||||||
|
do {
|
||||||
|
list.add(getTagById(cursor.getLong(0)));
|
||||||
|
} while (cursor.moveToNext());
|
||||||
|
cursor.close();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myGetSeriesIdStatement;
|
||||||
|
private SQLiteStatement myInsertSeriesStatement;
|
||||||
|
private SQLiteStatement myInsertBookSeriesStatement;
|
||||||
|
private SQLiteStatement myDeleteBookSeriesStatement;
|
||||||
|
public void saveBookSeriesInfo(long bookId, SeriesInfo seriesInfo) {
|
||||||
|
if (myGetSeriesIdStatement == null) {
|
||||||
|
myGetSeriesIdStatement = myDatabase.compileStatement(
|
||||||
|
"SELECT series_id FROM Series WHERE name = ?"
|
||||||
|
);
|
||||||
|
myInsertSeriesStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT INTO Series (name) VALUES (?)"
|
||||||
|
);
|
||||||
|
myInsertBookSeriesStatement = myDatabase.compileStatement(
|
||||||
|
"INSERT OR REPLACE INTO BookSeries (book_id,series_id,book_index) VALUES (?,?,?)"
|
||||||
|
);
|
||||||
|
myDeleteBookSeriesStatement = myDatabase.compileStatement(
|
||||||
|
"DELETE FROM BookSeries WHERE book_id = ?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seriesInfo == null) {
|
||||||
|
myDeleteBookSeriesStatement.bindLong(1, bookId);
|
||||||
|
myDeleteBookSeriesStatement.execute();
|
||||||
|
} else {
|
||||||
|
long seriesId;
|
||||||
|
try {
|
||||||
|
myGetSeriesIdStatement.bindString(1, seriesInfo.Name);
|
||||||
|
seriesId = myGetSeriesIdStatement.simpleQueryForLong();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
myInsertSeriesStatement.bindString(1, seriesInfo.Name);
|
||||||
|
seriesId = myInsertSeriesStatement.executeInsert();
|
||||||
|
}
|
||||||
|
myInsertBookSeriesStatement.bindLong(1, bookId);
|
||||||
|
myInsertBookSeriesStatement.bindLong(2, seriesId);
|
||||||
|
myInsertBookSeriesStatement.bindLong(3, seriesInfo.Index);
|
||||||
|
myInsertBookSeriesStatement.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeriesInfo loadSeriesInfo(long bookId) {
|
||||||
|
final Cursor cursor = myDatabase.rawQuery("SELECT Series.name,BookSeries.book_index FROM BookSeries INNER JOIN Series ON Series.series_id = BookSeries.series_id WHERE BookSeries.book_id = ?", new String[] { "" + bookId });
|
||||||
|
SeriesInfo info = null;
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
info = new SeriesInfo(cursor.getString(0), cursor.getLong(1));
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteStatement myResetBookInfoStatement;
|
||||||
|
private final static String myBookIdWhereClause = "book_id = ?";
|
||||||
|
public void resetBookInfo(String fileName) {
|
||||||
|
if (myResetBookInfoStatement == null) {
|
||||||
|
myResetBookInfoStatement = myDatabase.compileStatement(
|
||||||
|
"SELECT book_id FROM Books WHERE file_name = ?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
myResetBookInfoStatement.bindString(1, fileName);
|
||||||
|
try {
|
||||||
|
final long bookId = myResetBookInfoStatement.simpleQueryForLong();
|
||||||
|
final String[] parameters = { "" + bookId };
|
||||||
|
executeAsATransaction(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
myDatabase.delete("Books", myBookIdWhereClause, parameters);
|
||||||
|
myDatabase.delete("BookAuthor", myBookIdWhereClause, parameters);
|
||||||
|
myDatabase.delete("BookSeries", myBookIdWhereClause, parameters);
|
||||||
|
myDatabase.delete("BookTag", myBookIdWhereClause, parameters);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (SQLException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,8 +21,7 @@ package org.geometerplus.android.fbreader;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.*;
|
import android.view.*;
|
||||||
import android.widget.TextView;
|
import android.widget.*;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
import android.content.res.TypedArray;
|
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.application.ZLApplication;
|
||||||
import org.geometerplus.zlibrary.core.tree.ZLTree;
|
import org.geometerplus.zlibrary.core.tree.ZLTree;
|
||||||
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
|
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.ui.android.R;
|
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.FBReader;
|
||||||
import org.geometerplus.fbreader.fbreader.BookTextView;
|
import org.geometerplus.fbreader.fbreader.BookTextView;
|
||||||
|
|
||||||
public class TOCActivity extends ListActivity {
|
public class TOCActivity extends ListActivity {
|
||||||
|
private TOCAdapter myAdapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle bundle) {
|
public void onCreate(Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
final FBReader fbreader = (FBReader)ZLApplication.Instance();
|
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();
|
int selectedIndex = adapter.getSelectedIndex();
|
||||||
if (selectedIndex >= 0) {
|
if (selectedIndex >= 0) {
|
||||||
|
@ -54,31 +77,69 @@ public class TOCActivity extends ListActivity {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class TOCAdapter extends ZLTreeAdapter {
|
private static final int PROCESS_TREE_ITEM_ID = 0;
|
||||||
private final ContentsTree myContentsTree;
|
private static final int READ_BOOK_ITEM_ID = 1;
|
||||||
|
|
||||||
TOCAdapter(ContentsTree tree) {
|
@Override
|
||||||
super(getListView(), tree);
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
myContentsTree = tree;
|
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) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
final View view = (convertView != null) ? convertView :
|
final View view = (convertView != null) ? convertView :
|
||||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.toc_tree_item, parent, false);
|
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);
|
setIcon((ImageView)view.findViewById(R.id.toc_tree_item_icon), tree);
|
||||||
((TextView)view.findViewById(R.id.toc_tree_item_text)).setText(tree.getText());
|
((TextView)view.findViewById(R.id.toc_tree_item_text)).setText(tree.getText());
|
||||||
return view;
|
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) {
|
protected boolean runTreeItem(ZLTree tree) {
|
||||||
if (super.runTreeItem(tree)) {
|
if (super.runTreeItem(tree)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final ContentsTree.Reference reference = myContentsTree.getReference((ZLStringTree)tree);
|
openBookText((TOCTree)tree);
|
||||||
final FBReader fbreader = (FBReader)ZLApplication.Instance();
|
|
||||||
fbreader.BookTextView.gotoParagraphSafe(reference.Model, reference.ParagraphIndex);
|
|
||||||
finish();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.geometerplus.zlibrary.core.tree.ZLTree;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.ui.android.R;
|
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 ListView myParent;
|
||||||
private final ZLTree myTree;
|
private final ZLTree myTree;
|
||||||
private final ZLTree[] myItems;
|
private final ZLTree[] myItems;
|
||||||
|
@ -56,14 +56,52 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
|
||||||
myOpenItems.add(tree);
|
myOpenItems.add(tree);
|
||||||
|
|
||||||
parent.setAdapter(this);
|
parent.setAdapter(this);
|
||||||
parent.setOnKeyListener(this);
|
|
||||||
parent.setOnItemClickListener(this);
|
parent.setOnItemClickListener(this);
|
||||||
parent.setOnCreateContextMenuListener(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) {
|
private int getCount(ZLTree<?> tree) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
if (myOpenItems.contains(tree)) {
|
if (isOpen(tree)) {
|
||||||
for (ZLTree subtree : tree.subTrees()) {
|
for (ZLTree subtree : tree.subTrees()) {
|
||||||
count += getCount(subtree);
|
count += getCount(subtree);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +157,7 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
|
||||||
if (!tree.hasChildren()) {
|
if (!tree.hasChildren()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (myOpenItems.contains(tree)) {
|
if (isOpen(tree)) {
|
||||||
myOpenItems.remove(tree);
|
myOpenItems.remove(tree);
|
||||||
} else {
|
} else {
|
||||||
myOpenItems.add(tree);
|
myOpenItems.add(tree);
|
||||||
|
@ -136,38 +174,13 @@ abstract class ZLTreeAdapter extends BaseAdapter implements AdapterView.OnItemCl
|
||||||
private boolean myContextMenuInProgress;
|
private boolean myContextMenuInProgress;
|
||||||
|
|
||||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
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) {
|
public abstract View getView(int position, View convertView, ViewGroup parent);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void setIcon(ImageView imageView, ZLTree tree) {
|
protected final void setIcon(ImageView imageView, ZLTree tree) {
|
||||||
if (tree.hasChildren()) {
|
if (tree.hasChildren()) {
|
||||||
if (myOpenItems.contains(tree)) {
|
if (isOpen(tree)) {
|
||||||
imageView.setImageResource(R.drawable.tree_icon_group_open);
|
imageView.setImageResource(R.drawable.tree_icon_group_open);
|
||||||
} else {
|
} else {
|
||||||
imageView.setImageResource(R.drawable.tree_icon_group_closed);
|
imageView.setImageResource(R.drawable.tree_icon_group_closed);
|
||||||
|
|
|
@ -26,13 +26,13 @@ import org.geometerplus.zlibrary.core.image.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.model.*;
|
import org.geometerplus.zlibrary.text.model.*;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.formats.*;
|
import org.geometerplus.fbreader.formats.*;
|
||||||
|
|
||||||
public final class BookModel {
|
public final class BookModel {
|
||||||
public final BookDescription Description;
|
public final BookDescription Description;
|
||||||
public final ZLTextPlainModel BookTextModel = new ZLTextPlainModel(65536, "/sdcard/Books/.FBReader", "cache");
|
public final ZLTextPlainModel BookTextModel = new ZLTextPlainModel(65536, "/sdcard/Books/.FBReader", "cache");
|
||||||
public final ContentsTree ContentsTree = new ContentsTree();
|
public final TOCTree TOCTree = new TOCTree();
|
||||||
|
|
||||||
private final HashMap<String,ZLTextPlainModel> myFootnotes = new HashMap<String,ZLTextPlainModel>();
|
private final HashMap<String,ZLTextPlainModel> myFootnotes = new HashMap<String,ZLTextPlainModel>();
|
||||||
private final HashMap myInternalHyperlinks = new HashMap();
|
private final HashMap myInternalHyperlinks = new HashMap();
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.geometerplus.zlibrary.core.util.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.image.ZLImage;
|
import org.geometerplus.zlibrary.core.image.ZLImage;
|
||||||
import org.geometerplus.zlibrary.text.model.*;
|
import org.geometerplus.zlibrary.text.model.*;
|
||||||
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
|
|
||||||
|
|
||||||
public class BookReader {
|
public class BookReader {
|
||||||
public final BookModel Model;
|
public final BookModel Model;
|
||||||
|
@ -46,11 +45,11 @@ public class BookReader {
|
||||||
private boolean myInsideTitle = false;
|
private boolean myInsideTitle = false;
|
||||||
private boolean mySectionContainsRegularContents = false;
|
private boolean mySectionContainsRegularContents = false;
|
||||||
|
|
||||||
private ZLStringTree myCurrentContentsTree;
|
private TOCTree myCurrentContentsTree;
|
||||||
|
|
||||||
public BookReader(BookModel model) {
|
public BookReader(BookModel model) {
|
||||||
Model = model;
|
Model = model;
|
||||||
myCurrentContentsTree = model.ContentsTree;
|
myCurrentContentsTree = model.TOCTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void flushTextBufferToParagraph() {
|
private final void flushTextBufferToParagraph() {
|
||||||
|
@ -242,7 +241,7 @@ public class BookReader {
|
||||||
if (referenceNumber == -1) {
|
if (referenceNumber == -1) {
|
||||||
referenceNumber = textModel.getParagraphsNumber();
|
referenceNumber = textModel.getParagraphsNumber();
|
||||||
}
|
}
|
||||||
ZLStringTree parentTree = myCurrentContentsTree;
|
TOCTree parentTree = myCurrentContentsTree;
|
||||||
if (parentTree.getLevel() > 0) {
|
if (parentTree.getLevel() > 0) {
|
||||||
final ZLTextBuffer contentsBuffer = myContentsBuffer;
|
final ZLTextBuffer contentsBuffer = myContentsBuffer;
|
||||||
if (!contentsBuffer.isEmpty()) {
|
if (!contentsBuffer.isEmpty()) {
|
||||||
|
@ -254,14 +253,14 @@ public class BookReader {
|
||||||
} else {
|
} else {
|
||||||
myContentsBuffer.clear();
|
myContentsBuffer.clear();
|
||||||
}
|
}
|
||||||
ZLStringTree tree = parentTree.createSubTree();
|
TOCTree tree = parentTree.createSubTree();
|
||||||
Model.ContentsTree.setReference(tree, myCurrentTextModel, referenceNumber);
|
tree.setReference(myCurrentTextModel, referenceNumber);
|
||||||
myCurrentContentsTree = tree;
|
myCurrentContentsTree = tree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void endContentsParagraph() {
|
public final void endContentsParagraph() {
|
||||||
final ZLStringTree tree = myCurrentContentsTree;
|
final TOCTree tree = myCurrentContentsTree;
|
||||||
final ZLTextBuffer contentsBuffer = myContentsBuffer;
|
final ZLTextBuffer contentsBuffer = myContentsBuffer;
|
||||||
if (tree.getLevel() == 0) {
|
if (tree.getLevel() == 0) {
|
||||||
contentsBuffer.clear();
|
contentsBuffer.clear();
|
||||||
|
@ -281,10 +280,10 @@ public class BookReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setReference(int contentsParagraphNumber, ZLTextModel textModel, int referenceNumber) {
|
public final void setReference(int contentsParagraphNumber, ZLTextModel textModel, int referenceNumber) {
|
||||||
final ContentsTree contentsTree = Model.ContentsTree;
|
final TOCTree contentsTree = Model.TOCTree;
|
||||||
if (contentsParagraphNumber < contentsTree.getSize()) {
|
if (contentsParagraphNumber < contentsTree.getSize()) {
|
||||||
contentsTree.setReference(
|
contentsTree.getTree(contentsParagraphNumber).setReference(
|
||||||
contentsTree.getTree(contentsParagraphNumber), textModel, referenceNumber
|
textModel, referenceNumber
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
|
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,21 +19,42 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.bookmodel;
|
package org.geometerplus.fbreader.bookmodel;
|
||||||
|
|
||||||
import java.util.*;
|
import org.geometerplus.zlibrary.core.tree.ZLTree;
|
||||||
import org.geometerplus.zlibrary.core.util.*;
|
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.model.ZLTextModel;
|
import org.geometerplus.zlibrary.text.model.ZLTextModel;
|
||||||
import org.geometerplus.zlibrary.core.tree.ZLStringTree;
|
|
||||||
|
|
||||||
public class ContentsTree extends ZLStringTree {
|
public class TOCTree extends ZLTree<TOCTree> {
|
||||||
private final HashMap<ZLStringTree,Reference> myReferenceByTree = new HashMap<ZLStringTree,Reference>();
|
private String myText;
|
||||||
|
private Reference myReference;
|
||||||
|
|
||||||
public Reference getReference(ZLStringTree tree) {
|
protected TOCTree() {
|
||||||
return myReferenceByTree.get(tree);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReference(ZLStringTree tree, ZLTextModel model, int reference) {
|
private TOCTree(TOCTree parent) {
|
||||||
myReferenceByTree.put(tree, new Reference(reference, model));
|
super(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getText() {
|
||||||
|
return myText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setText(String text) {
|
||||||
|
myText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reference getReference() {
|
||||||
|
return myReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReference(ZLTextModel model, int reference) {
|
||||||
|
myReference = new Reference(reference, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final TOCTree createSubTree() {
|
||||||
|
TOCTree subtree = new TOCTree(this);
|
||||||
|
addSubTree(subtree);
|
||||||
|
return subtree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Reference {
|
public static class Reference {
|
|
@ -1,167 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.fbreader.booksdb;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
|
|
||||||
public final class BookInfo {
|
|
||||||
private static boolean equals(Object o0, Object o1) {
|
|
||||||
if (o0 == null) {
|
|
||||||
return o1 == null;
|
|
||||||
}
|
|
||||||
return o0.equals(o1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final SQLiteDatabase myDatabase = BooksDatabase.Instance().Database;
|
|
||||||
|
|
||||||
private String myBookId;
|
|
||||||
|
|
||||||
public final String FileName;
|
|
||||||
|
|
||||||
private String myTitle;
|
|
||||||
private String myAuthorName;
|
|
||||||
private String myAuthorSortKey;
|
|
||||||
private String myLanguage;
|
|
||||||
private String myEncoding;
|
|
||||||
private String mySeries;
|
|
||||||
private int myNumberInSeries;
|
|
||||||
|
|
||||||
private boolean myIsSaved;
|
|
||||||
private boolean myIsChanged;
|
|
||||||
|
|
||||||
public BookInfo(String fileName) {
|
|
||||||
FileName = fileName;
|
|
||||||
// TODO: implement
|
|
||||||
myTitle = "";
|
|
||||||
myLanguage = "";
|
|
||||||
myEncoding = "";
|
|
||||||
myAuthorName = "";
|
|
||||||
myAuthorSortKey = "";
|
|
||||||
myIsSaved = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSaved() {
|
|
||||||
return myIsSaved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save() {
|
|
||||||
if (myIsChanged) {
|
|
||||||
// TODO: implement
|
|
||||||
myIsChanged = false;
|
|
||||||
//myIsSaved = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
final String whereClause = "book_id = ?";
|
|
||||||
final String[] parameters = new String[] { myBookId };
|
|
||||||
myDatabase.delete("Books", whereClause, parameters);
|
|
||||||
myDatabase.delete("BookAuthor", whereClause, parameters);
|
|
||||||
myDatabase.delete("BookSeries", whereClause, parameters);
|
|
||||||
myDatabase.delete("BookTag", whereClause, parameters);
|
|
||||||
myTitle = "";
|
|
||||||
myLanguage = "";
|
|
||||||
myEncoding = "";
|
|
||||||
myAuthorName = "";
|
|
||||||
myAuthorSortKey = "";
|
|
||||||
mySeries = null;
|
|
||||||
myNumberInSeries = 0;
|
|
||||||
myIsChanged = false;
|
|
||||||
myIsSaved = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return myTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
if (!myTitle.equals(title)) {
|
|
||||||
myTitle = title;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthorName() {
|
|
||||||
return myAuthorName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthorName(String authorName) {
|
|
||||||
if (!myAuthorName.equals(authorName)) {
|
|
||||||
myAuthorName = authorName;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthorSortKey() {
|
|
||||||
return myAuthorSortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthorSortKey(String authorSortKey) {
|
|
||||||
if (!myAuthorSortKey.equals(authorSortKey)) {
|
|
||||||
myAuthorSortKey = authorSortKey;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return myLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLanguage(String language) {
|
|
||||||
if (!myLanguage.equals(language)) {
|
|
||||||
myLanguage = language;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return myEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEncoding(String encoding) {
|
|
||||||
if (!myEncoding.equals(encoding)) {
|
|
||||||
myEncoding = encoding;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSeries() {
|
|
||||||
return mySeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSeries(String series) {
|
|
||||||
if (!equals(mySeries, series)) {
|
|
||||||
mySeries = series;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberInSeries() {
|
|
||||||
return myNumberInSeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumberInSeries(int numberInSeries) {
|
|
||||||
if (myNumberInSeries != numberInSeries) {
|
|
||||||
myNumberInSeries = numberInSeries;
|
|
||||||
myIsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.fbreader.booksdb;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication;
|
|
||||||
|
|
||||||
class BooksDatabase {
|
|
||||||
private static BooksDatabase ourInstance;
|
|
||||||
|
|
||||||
static BooksDatabase Instance() {
|
|
||||||
if (ourInstance == null) {
|
|
||||||
ourInstance = new BooksDatabase(ZLAndroidApplication.Instance());
|
|
||||||
}
|
|
||||||
return ourInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
final SQLiteDatabase Database;
|
|
||||||
|
|
||||||
private BooksDatabase(Context context) {
|
|
||||||
Database = context.openOrCreateDatabase("books.db", Context.MODE_PRIVATE, null);
|
|
||||||
if (Database.getVersion() == 0) {
|
|
||||||
Database.beginTransaction();
|
|
||||||
/*
|
|
||||||
Database.execSQL("DROP TABLE Books");
|
|
||||||
Database.execSQL("DROP TABLE Authors");
|
|
||||||
Database.execSQL("DROP TABLE Series");
|
|
||||||
Database.execSQL("DROP TABLE Tags");
|
|
||||||
Database.execSQL("DROP TABLE BookAuthor");
|
|
||||||
Database.execSQL("DROP TABLE BookSeries");
|
|
||||||
Database.execSQL("DROP TABLE BookTag");
|
|
||||||
*/
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE Books(" +
|
|
||||||
"book_id INTEGER PRIMARY KEY," +
|
|
||||||
"encoding TEXT," +
|
|
||||||
"lenguage TEXT," +
|
|
||||||
"title TEXT NOT NULL," +
|
|
||||||
"file_name TEXT UNIQUE NOT NULL)");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE Authors(" +
|
|
||||||
"author_id INTEGER PRIMARY KEY," +
|
|
||||||
"name TEXT NOT NULL," +
|
|
||||||
"sort_key TEXT NOT NULL," +
|
|
||||||
"CONSTRAINT Authors_Unique UNIQUE (name, sort_key))");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE BookAuthor(" +
|
|
||||||
"author_id INTEGER NOT NULL REFERENCES Authors(author_id)," +
|
|
||||||
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
|
|
||||||
"CONSTRAINT BookAuthor_Unique UNIQUE (author_id, book_id))");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE Series(" +
|
|
||||||
"series_id INTEGER PRIMARY KEY," +
|
|
||||||
"name TEXT UNIQUE NOT NULL)");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE BookSeries(" +
|
|
||||||
"series_id INTEGER NOT NULL REFERENCES Series(series_id)," +
|
|
||||||
"book_id INTEGER NOT NULL REFERENCES Books(book_id)," +
|
|
||||||
"number_in_series INTEGER," +
|
|
||||||
"CONSTRAINT BookSeries_Unique UNIQUE (series_id, book_id))");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE Tags(" +
|
|
||||||
"tag_id INTEGER PRIMARY KEY," +
|
|
||||||
"name TEXT NOT NULL," +
|
|
||||||
"parent INTEGER REFERENCES Tags(tag_id)," +
|
|
||||||
"CONSTRAINT Tags_Unique UNIQUE (name, parent))");
|
|
||||||
Database.execSQL(
|
|
||||||
"CREATE TABLE BookTag(" +
|
|
||||||
"tag_id INTEGER REFERENCES Tags(tag_id)," +
|
|
||||||
"book_id INTEGER REFERENCES Books(book_id)," +
|
|
||||||
"CONSTRAINT BookTag_Unique UNIQUE (tag_id, book_id))");
|
|
||||||
Database.setTransactionSuccessful();
|
|
||||||
Database.endTransaction();
|
|
||||||
|
|
||||||
Database.setVersion(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,7 @@
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geometerplus.fbreader.description;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.geometerplus.zlibrary.core.util.*;
|
import org.geometerplus.zlibrary.core.util.*;
|
||||||
|
@ -26,15 +26,12 @@ public final class Author {
|
||||||
public final String DisplayName;
|
public final String DisplayName;
|
||||||
public final String SortKey;
|
public final String SortKey;
|
||||||
|
|
||||||
Author(String displayName, String sortKey) {
|
public Author(String displayName, String sortKey) {
|
||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
SortKey = sortKey;
|
SortKey = sortKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
Author() {
|
@Override
|
||||||
this("Unknown Author", "___");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o == this) {
|
if (o == this) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -46,6 +43,7 @@ public final class Author {
|
||||||
return SortKey.equals(a.SortKey) && DisplayName.equals(a.DisplayName);
|
return SortKey.equals(a.SortKey) && DisplayName.equals(a.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return SortKey.hashCode() + DisplayName.hashCode();
|
return SortKey.hashCode() + DisplayName.hashCode();
|
||||||
}
|
}
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.collection;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.Author;
|
|
||||||
|
|
||||||
public class AuthorTree extends CollectionTree {
|
public class AuthorTree extends CollectionTree {
|
||||||
private final Author myAuthor;
|
private final Author myAuthor;
|
||||||
|
|
||||||
|
@ -36,10 +34,11 @@ public class AuthorTree extends CollectionTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return myAuthor.DisplayName;
|
// TODO: use resources
|
||||||
|
return (myAuthor != null) ? myAuthor.DisplayName : "Unknown Author";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSortKey() {
|
protected String getSortKey() {
|
||||||
return myAuthor.SortKey;
|
return (myAuthor != null) ? myAuthor.SortKey : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,8 @@ package org.geometerplus.fbreader.collection;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.geometerplus.zlibrary.core.util.*;
|
import org.geometerplus.zlibrary.core.util.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.config.ZLConfig;
|
|
||||||
import org.geometerplus.zlibrary.core.filesystem.*;
|
import org.geometerplus.zlibrary.core.filesystem.*;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.*;
|
|
||||||
import org.geometerplus.fbreader.formats.PluginCollection;
|
import org.geometerplus.fbreader.formats.PluginCollection;
|
||||||
|
|
||||||
public class BookCollection {
|
public class BookCollection {
|
||||||
|
@ -115,51 +113,63 @@ public class BookCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final ArrayList ourNullList = new ArrayList(1);
|
||||||
|
static {
|
||||||
|
ourNullList.add(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TagTree getTagTree(Tag tag, HashMap<Tag,TagTree> tagTreeMap) {
|
||||||
|
TagTree tagTree = tagTreeMap.get(tag);
|
||||||
|
if (tagTree == null) {
|
||||||
|
CollectionTree parent =
|
||||||
|
((tag != null) && (tag.Parent != null)) ?
|
||||||
|
getTagTree(tag.Parent, tagTreeMap) : myCollectionByTag;
|
||||||
|
tagTree = parent.createTagSubTree(tag);
|
||||||
|
tagTreeMap.put(tag, tagTree);
|
||||||
|
}
|
||||||
|
return tagTree;
|
||||||
|
}
|
||||||
|
|
||||||
private void build() {
|
private void build() {
|
||||||
final HashSet fileNamesSet = collectBookFileNames();
|
final HashSet fileNamesSet = collectBookFileNames();
|
||||||
final HashMap<String,TagTree> tagTreeMap = new HashMap<String,TagTree>();
|
final HashMap<Tag,TagTree> tagTreeMap = new HashMap<Tag,TagTree>();
|
||||||
final HashMap<Author,AuthorTree> authorTreeMap = new HashMap<Author,AuthorTree>();
|
final HashMap<Author,AuthorTree> authorTreeMap = new HashMap<Author,AuthorTree>();
|
||||||
final HashMap<AuthorSeriesPair,SeriesTree> seriesTreeMap = new HashMap<AuthorSeriesPair,SeriesTree>();
|
final HashMap<AuthorSeriesPair,SeriesTree> seriesTreeMap = new HashMap<AuthorSeriesPair,SeriesTree>();
|
||||||
|
|
||||||
for (Iterator it = fileNamesSet.iterator(); it.hasNext(); ) {
|
for (Iterator it = fileNamesSet.iterator(); it.hasNext(); ) {
|
||||||
final BookDescription description = BookDescription.getDescription((String)it.next());
|
final BookDescription description = BookDescription.getDescription((String)it.next());
|
||||||
|
|
||||||
final Author author = description.getAuthor();
|
List<Author> authors = description.authors();
|
||||||
final String series = description.getSeriesName();
|
if (authors.isEmpty()) {
|
||||||
AuthorTree authorTree = authorTreeMap.get(author);
|
authors = (List<Author>)ourNullList;
|
||||||
if (authorTree == null) {
|
|
||||||
authorTree = myCollectionByAuthor.createAuthorSubTree(author);
|
|
||||||
authorTreeMap.put(author, authorTree);
|
|
||||||
}
|
}
|
||||||
if (series.length() == 0) {
|
final SeriesInfo seriesInfo = description.getSeriesInfo();
|
||||||
authorTree.createBookSubTree(description);
|
for (Author a : authors) {
|
||||||
} else {
|
AuthorTree authorTree = authorTreeMap.get(a);
|
||||||
final AuthorSeriesPair pair = new AuthorSeriesPair(author, series);
|
if (authorTree == null) {
|
||||||
SeriesTree seriesTree = seriesTreeMap.get(pair);
|
authorTree = myCollectionByAuthor.createAuthorSubTree(a);
|
||||||
if (seriesTree == null) {
|
authorTreeMap.put(a, authorTree);
|
||||||
seriesTree = authorTree.createSeriesSubTree(series);
|
}
|
||||||
seriesTreeMap.put(pair, seriesTree);
|
if (seriesInfo == null) {
|
||||||
|
authorTree.createBookSubTree(description);
|
||||||
|
} else {
|
||||||
|
final String series = seriesInfo.Name;
|
||||||
|
final AuthorSeriesPair pair = new AuthorSeriesPair(a, series);
|
||||||
|
SeriesTree seriesTree = seriesTreeMap.get(pair);
|
||||||
|
if (seriesTree == null) {
|
||||||
|
seriesTree = authorTree.createSeriesSubTree(series);
|
||||||
|
seriesTreeMap.put(pair, seriesTree);
|
||||||
|
}
|
||||||
|
seriesTree.createBookInSeriesSubTree(description);
|
||||||
}
|
}
|
||||||
seriesTree.createBookInSeriesSubTree(description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> tags = description.getTags();
|
List<Tag> tags = description.tags();
|
||||||
if (!tags.isEmpty()) {
|
if (tags.isEmpty()) {
|
||||||
for (String tag : description.getTags()) {
|
tags = (List<Tag>)ourNullList;
|
||||||
TagTree tagTree = tagTreeMap.get(tag);
|
}
|
||||||
if (tagTree == null) {
|
for (Tag t : tags) {
|
||||||
tagTree = myCollectionByTag.createTagSubTree(tag);
|
getTagTree(t, tagTreeMap).createBookSubTree(description);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +179,7 @@ public class BookCollection {
|
||||||
myCollectionByAuthor.clear();
|
myCollectionByAuthor.clear();
|
||||||
myCollectionByTag.clear();
|
myCollectionByTag.clear();
|
||||||
|
|
||||||
ZLConfig.Instance().executeAsATransaction(new Runnable() {
|
BooksDatabase.Instance().executeAsATransaction(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
257
src/org/geometerplus/fbreader/collection/BookDescription.java
Normal file
257
src/org/geometerplus/fbreader/collection/BookDescription.java
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.formats.*;
|
||||||
|
|
||||||
|
public class BookDescription {
|
||||||
|
public final String FileName;
|
||||||
|
|
||||||
|
private long myBookId;
|
||||||
|
|
||||||
|
private String myEncoding;
|
||||||
|
private String myLanguage;
|
||||||
|
private String myTitle;
|
||||||
|
private ArrayList<Author> myAuthors;
|
||||||
|
private ArrayList<Tag> myTags;
|
||||||
|
private SeriesInfo mySeriesInfo;
|
||||||
|
|
||||||
|
private boolean myIsSaved;
|
||||||
|
private boolean myIsChanged;
|
||||||
|
|
||||||
|
private final static HashMap<String,BookDescription> ourDescriptions = new HashMap<String,BookDescription>();
|
||||||
|
|
||||||
|
public static BookDescription getDescription(String fileName) {
|
||||||
|
return getDescription(fileName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BookDescription getDescription(String fileName, boolean checkFile) {
|
||||||
|
if (fileName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String physicalFileName = new ZLFile(fileName).getPhysicalFilePath();
|
||||||
|
ZLFile file = new ZLFile(physicalFileName);
|
||||||
|
if (checkFile && !file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BookDescription description = ourDescriptions.get(fileName);
|
||||||
|
if (description == null) {
|
||||||
|
description = new BookDescription(fileName);
|
||||||
|
ourDescriptions.put(fileName, description);
|
||||||
|
}
|
||||||
|
if ((!checkFile || BookDescriptionUtil.checkInfo(file)) && description.isSaved()) {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physicalFileName != fileName) {
|
||||||
|
BookDescriptionUtil.resetZipInfo(file);
|
||||||
|
}
|
||||||
|
BookDescriptionUtil.saveInfo(file);
|
||||||
|
|
||||||
|
ZLFile bookFile = new ZLFile(fileName);
|
||||||
|
|
||||||
|
FormatPlugin plugin = PluginCollection.instance().getPlugin(bookFile, false);
|
||||||
|
if ((plugin == null) || !plugin.readDescription(fileName, description)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = description.getTitle();
|
||||||
|
if ((title == null) || (title.length() == 0)) {
|
||||||
|
description.setTitle(bookFile.getName(true));
|
||||||
|
}
|
||||||
|
description.save();
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BookDescription(String fileName) {
|
||||||
|
FileName = fileName;
|
||||||
|
final BooksDatabase database = BooksDatabase.Instance();
|
||||||
|
myBookId = database.loadBook(this);
|
||||||
|
if (myBookId >= 0) {
|
||||||
|
myAuthors = database.loadAuthors(myBookId);
|
||||||
|
myTags = database.loadTags(myBookId);
|
||||||
|
mySeriesInfo = database.loadSeriesInfo(myBookId);
|
||||||
|
myIsSaved = true;
|
||||||
|
myIsChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSaved() {
|
||||||
|
return myIsSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Author> authors() {
|
||||||
|
return (myAuthors != null) ? Collections.unmodifiableList(myAuthors) : Collections.<Author>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAuthor(Author author) {
|
||||||
|
if (author == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (myAuthors == null) {
|
||||||
|
myAuthors = new ArrayList<Author>();
|
||||||
|
myAuthors.add(author);
|
||||||
|
myIsChanged = true;
|
||||||
|
} else {
|
||||||
|
if (!myAuthors.contains(author)) {
|
||||||
|
myAuthors.add(author);
|
||||||
|
myIsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAuthor(String name) {
|
||||||
|
addAuthor(name, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAuthor(String name, String sortKey) {
|
||||||
|
String strippedName = name;
|
||||||
|
strippedName.trim();
|
||||||
|
if (strippedName.length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String strippedKey = sortKey;
|
||||||
|
strippedKey.trim();
|
||||||
|
if (strippedKey.length() == 0) {
|
||||||
|
int index = strippedName.lastIndexOf(' ');
|
||||||
|
if (index == -1) {
|
||||||
|
strippedKey = strippedName;
|
||||||
|
} else {
|
||||||
|
strippedKey = strippedName.substring(index + 1);
|
||||||
|
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addAuthor(new Author(strippedName, strippedKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return myTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
if (!equals(myTitle, title)) {
|
||||||
|
myTitle = title;
|
||||||
|
myIsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeriesInfo getSeriesInfo() {
|
||||||
|
return mySeriesInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeriesInfo(String name, long index) {
|
||||||
|
if (mySeriesInfo == null) {
|
||||||
|
if (name != null) {
|
||||||
|
mySeriesInfo = new SeriesInfo(name, index);
|
||||||
|
}
|
||||||
|
} else if (name == null) {
|
||||||
|
mySeriesInfo = null;
|
||||||
|
} else if (!mySeriesInfo.Name.equals(name) || (mySeriesInfo.Index != index)) {
|
||||||
|
mySeriesInfo = new SeriesInfo(name, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLanguage() {
|
||||||
|
return myLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLanguage(String language) {
|
||||||
|
if (!equals(myLanguage, language)) {
|
||||||
|
myLanguage = language;
|
||||||
|
myIsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEncoding() {
|
||||||
|
return myEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEncoding(String encoding) {
|
||||||
|
if (!equals(myEncoding, encoding)) {
|
||||||
|
myEncoding = encoding;
|
||||||
|
myIsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tag> tags() {
|
||||||
|
return (myTags != null) ? Collections.unmodifiableList(myTags) : Collections.<Tag>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTag(Tag tag) {
|
||||||
|
if (tag != null) {
|
||||||
|
if (myTags == null) {
|
||||||
|
myTags = new ArrayList<Tag>();
|
||||||
|
}
|
||||||
|
if (!myTags.contains(tag)) {
|
||||||
|
myTags.add(tag);
|
||||||
|
myIsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTag(String tagName) {
|
||||||
|
addTag(Tag.getTag(null, tagName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
if (!myIsChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final BooksDatabase database = BooksDatabase.Instance();
|
||||||
|
database.executeAsATransaction(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (myBookId >= 0) {
|
||||||
|
database.updateBookInfo(myBookId, myEncoding, myLanguage, myTitle);
|
||||||
|
} else {
|
||||||
|
myBookId = database.insertBookInfo(FileName, myEncoding, myLanguage, myTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
long index = 0;
|
||||||
|
for (Author author : authors()) {
|
||||||
|
database.saveBookAuthorInfo(myBookId, index++, author);
|
||||||
|
}
|
||||||
|
for (Tag tag : tags()) {
|
||||||
|
database.saveBookTagInfo(myBookId, tag);
|
||||||
|
}
|
||||||
|
database.saveBookSeriesInfo(myBookId, mySeriesInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
myIsChanged = false;
|
||||||
|
myIsSaved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equals(Object o0, Object o1) {
|
||||||
|
if (o0 == null) {
|
||||||
|
return o1 == null;
|
||||||
|
}
|
||||||
|
return o0.equals(o1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,18 +17,18 @@
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geometerplus.fbreader.description;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.geometerplus.zlibrary.core.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.ZLDir;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
import org.geometerplus.zlibrary.core.options.ZLIntegerOption;
|
import org.geometerplus.zlibrary.core.options.ZLIntegerOption;
|
||||||
import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
||||||
|
|
||||||
|
import org.geometerplus.fbreader.formats.PluginCollection;
|
||||||
|
|
||||||
public class BookDescriptionUtil {
|
public class BookDescriptionUtil {
|
||||||
private static final String SIZE = "Size";
|
private static final String SIZE = "Size";
|
||||||
private static final String ENTRY = "Entry";
|
private static final String ENTRY = "Entry";
|
||||||
|
@ -37,7 +37,6 @@ public class BookDescriptionUtil {
|
||||||
public static boolean checkInfo(ZLFile file) {
|
public static boolean checkInfo(ZLFile file) {
|
||||||
ZLIntegerOption op = new ZLIntegerOption(file.getPath(), SIZE, -1);
|
ZLIntegerOption op = new ZLIntegerOption(file.getPath(), SIZE, -1);
|
||||||
return op.getValue() == (int)file.size();
|
return op.getValue() == (int)file.size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveInfo(ZLFile file) {
|
public static void saveInfo(ZLFile file) {
|
||||||
|
@ -47,7 +46,6 @@ public class BookDescriptionUtil {
|
||||||
public static void listZipEntries(ZLFile zipFile, ArrayList entries) {
|
public static void listZipEntries(ZLFile zipFile, ArrayList entries) {
|
||||||
int entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
|
int entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
|
||||||
if (entriesNumber == -1) {
|
if (entriesNumber == -1) {
|
||||||
//??? why so??resetZipInfo(zipFile.path());
|
|
||||||
resetZipInfo(zipFile);
|
resetZipInfo(zipFile);
|
||||||
entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
|
entriesNumber = new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).getValue();
|
||||||
}
|
}
|
||||||
|
@ -60,7 +58,6 @@ public class BookDescriptionUtil {
|
||||||
entries.add(entry);
|
entries.add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resetZipInfo(ZLFile zipFile) {
|
public static void resetZipInfo(ZLFile zipFile) {
|
||||||
|
@ -80,36 +77,11 @@ public class BookDescriptionUtil {
|
||||||
final String fullName = zipPrefix + entry;
|
final String fullName = zipPrefix + entry;
|
||||||
entryOption.changeName(ENTRY + counter);
|
entryOption.changeName(ENTRY + counter);
|
||||||
entryOption.setValue(fullName);
|
entryOption.setValue(fullName);
|
||||||
new BookInfo(fullName).reset();
|
BooksDatabase.Instance().resetBookInfo(fullName);
|
||||||
++counter;
|
++counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new ZLIntegerOption(zipFile.getPath(), ENTRIES_NUMBER, -1).setValue(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.collection;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
|
||||||
|
|
||||||
public final class BookInSeriesTree extends BookTree {
|
public final class BookInSeriesTree extends BookTree {
|
||||||
BookInSeriesTree(CollectionTree parent, BookDescription description) {
|
BookInSeriesTree(CollectionTree parent, BookDescription description) {
|
||||||
super(parent, description);
|
super(parent, description);
|
||||||
|
@ -29,9 +27,10 @@ public final class BookInSeriesTree extends BookTree {
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(CollectionTree tree) {
|
public int compareTo(CollectionTree tree) {
|
||||||
if (tree instanceof BookInSeriesTree) {
|
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) {
|
if (difference != 0) {
|
||||||
return difference;
|
return (int)difference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.compareTo(tree);
|
return super.compareTo(tree);
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.collection;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
|
||||||
|
|
||||||
public class BookTree extends CollectionTree {
|
public class BookTree extends CollectionTree {
|
||||||
public final BookDescription Description;
|
public final BookDescription Description;
|
||||||
|
|
||||||
|
|
46
src/org/geometerplus/fbreader/collection/BooksDatabase.java
Normal file
46
src/org/geometerplus/fbreader/collection/BooksDatabase.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public abstract class BooksDatabase {
|
||||||
|
private static BooksDatabase ourInstance;
|
||||||
|
|
||||||
|
static BooksDatabase Instance() {
|
||||||
|
return ourInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BooksDatabase() {
|
||||||
|
ourInstance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void executeAsATransaction(Runnable actions);
|
||||||
|
public abstract long loadBook(BookDescription description);
|
||||||
|
public abstract ArrayList<Author> loadAuthors(long bookId);
|
||||||
|
public abstract ArrayList<Tag> loadTags(long bookId);
|
||||||
|
public abstract SeriesInfo loadSeriesInfo(long bookId);
|
||||||
|
public abstract void updateBookInfo(long bookId, String encoding, String language, String title);
|
||||||
|
public abstract long insertBookInfo(String fileName, String encoding, String language, String title);
|
||||||
|
public abstract void saveBookAuthorInfo(long bookId, long index, Author author);
|
||||||
|
public abstract void saveBookTagInfo(long bookId, Tag tag);
|
||||||
|
public abstract void saveBookSeriesInfo(long bookId, SeriesInfo seriesInfo);
|
||||||
|
public abstract void resetBookInfo(String fileName);
|
||||||
|
}
|
|
@ -23,8 +23,6 @@ import java.util.Collections;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.tree.ZLTree;
|
import org.geometerplus.zlibrary.core.tree.ZLTree;
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
|
||||||
import org.geometerplus.fbreader.description.Author;
|
|
||||||
|
|
||||||
public abstract class CollectionTree extends ZLTree<CollectionTree> implements Comparable<CollectionTree> {
|
public abstract class CollectionTree extends ZLTree<CollectionTree> implements Comparable<CollectionTree> {
|
||||||
protected CollectionTree() {
|
protected CollectionTree() {
|
||||||
|
@ -35,7 +33,7 @@ public abstract class CollectionTree extends ZLTree<CollectionTree> implements C
|
||||||
super(parent);
|
super(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagTree createTagSubTree(String tag) {
|
TagTree createTagSubTree(Tag tag) {
|
||||||
TagTree tree = new TagTree(this, tag);
|
TagTree tree = new TagTree(this, tag);
|
||||||
addSubTree(tree);
|
addSubTree(tree);
|
||||||
return tree;
|
return tree;
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.geometerplus.zlibrary.core.util.*;
|
||||||
import org.geometerplus.zlibrary.core.config.ZLConfig;
|
import org.geometerplus.zlibrary.core.config.ZLConfig;
|
||||||
import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.*;
|
|
||||||
import org.geometerplus.fbreader.formats.PluginCollection;
|
import org.geometerplus.fbreader.formats.PluginCollection;
|
||||||
|
|
||||||
public final class RecentBooks {
|
public final class RecentBooks {
|
||||||
|
|
|
@ -17,32 +17,14 @@
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.core.tree;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
public final class SeriesInfo {
|
||||||
|
public final String Name;
|
||||||
|
public final long Index;
|
||||||
|
|
||||||
public class ZLStringTree extends ZLTree<ZLStringTree> {
|
public SeriesInfo(String name, long index) {
|
||||||
private String myText;
|
Name = name;
|
||||||
|
Index = index;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.collection;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
|
||||||
|
|
||||||
final class SeriesTree extends CollectionTree {
|
final class SeriesTree extends CollectionTree {
|
||||||
private final String mySeries;
|
private final String mySeries;
|
||||||
|
|
||||||
|
|
65
src/org/geometerplus/fbreader/collection/Tag.java
Normal file
65
src/org/geometerplus/fbreader/collection/Tag.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Geometer Plus <contact@geometerplus.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public final class Tag {
|
||||||
|
private static final HashMap<Tag,Tag> ourTagSet = new HashMap<Tag,Tag>();
|
||||||
|
|
||||||
|
public static Tag getTag(Tag parent, String name) {
|
||||||
|
if (name == null) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
name = name.trim();
|
||||||
|
if (name.length() == 0) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
Tag tag = new Tag(parent, name);
|
||||||
|
Tag stored = ourTagSet.get(tag);
|
||||||
|
if (stored != null) {
|
||||||
|
return stored;
|
||||||
|
}
|
||||||
|
ourTagSet.put(tag, tag);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Tag Parent;
|
||||||
|
public final String Name;
|
||||||
|
|
||||||
|
private Tag(Tag parent, String name) {
|
||||||
|
Parent = parent;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Tag)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Tag t = (Tag)o;
|
||||||
|
return (Parent == t.Parent) && Name.equals(t.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (Parent == null) ? Name.hashCode() : Parent.hashCode() + Name.hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,19 +20,19 @@
|
||||||
package org.geometerplus.fbreader.collection;
|
package org.geometerplus.fbreader.collection;
|
||||||
|
|
||||||
final class TagTree extends CollectionTree {
|
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);
|
super(parent);
|
||||||
myTag = tag;
|
myTag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
// TODO: use resources
|
// TODO: use resources
|
||||||
return (myTag != null) ? myTag : "Books with no tags";
|
return (myTag != null) ? myTag.Name : "Books with no tags";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSortKey() {
|
protected String getSortKey() {
|
||||||
return myTag;
|
return (myTag != null) ? myTag.Name : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,423 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.fbreader.description;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import org.geometerplus.zlibrary.core.util.*;
|
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
|
||||||
import org.geometerplus.zlibrary.core.options.*;
|
|
||||||
|
|
||||||
import org.geometerplus.fbreader.formats.*;
|
|
||||||
|
|
||||||
public class BookDescription {
|
|
||||||
private static final String EMPTY = "";
|
|
||||||
private static final String UNKNOWN = "unknown";
|
|
||||||
|
|
||||||
public final String FileName;
|
|
||||||
|
|
||||||
//private final TreeSet<Author> myAuthors = new TreeSet<Author>();
|
|
||||||
private Author myAuthor;
|
|
||||||
private String myTitle = "";
|
|
||||||
private String mySeriesName = "";
|
|
||||||
private int myNumberInSeries = 0;
|
|
||||||
private String myLanguage = "";
|
|
||||||
private String myEncoding = "";
|
|
||||||
private final static HashMap ourDescriptions = new HashMap();
|
|
||||||
private final ArrayList<String> myTags = new ArrayList<String>();
|
|
||||||
|
|
||||||
public static BookDescription getDescription(String fileName) {
|
|
||||||
return getDescription(fileName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BookDescription getDescription(String fileName, boolean checkFile) {
|
|
||||||
if (fileName == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String physicalFileName = new ZLFile(fileName).getPhysicalFilePath();
|
|
||||||
ZLFile file = new ZLFile(physicalFileName);
|
|
||||||
if (checkFile && !file.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
BookDescription description = (BookDescription)ourDescriptions.get(fileName);
|
|
||||||
if (description == null) {
|
|
||||||
description = new BookDescription(fileName);
|
|
||||||
ourDescriptions.put(fileName, description);
|
|
||||||
}
|
|
||||||
if (!checkFile || BookDescriptionUtil.checkInfo(file)) {
|
|
||||||
//if (false) {
|
|
||||||
BookInfo info = new BookInfo(fileName);
|
|
||||||
description.myAuthor = new Author(info.AuthorDisplayNameOption.getValue(), info.AuthorSortKeyOption.getValue());
|
|
||||||
description.myTitle = info.TitleOption.getValue();
|
|
||||||
description.mySeriesName = info.SeriesNameOption.getValue();
|
|
||||||
description.myNumberInSeries = info.NumberInSeriesOption.getValue();
|
|
||||||
description.myLanguage = info.LanguageOption.getValue();
|
|
||||||
description.myEncoding = info.EncodingOption.getValue();
|
|
||||||
description.myTags.clear();
|
|
||||||
final String tagList = info.TagsOption.getValue();
|
|
||||||
if (tagList.length() > 0) {
|
|
||||||
int index = 0;
|
|
||||||
do {
|
|
||||||
final int newIndex = tagList.indexOf(',', index);
|
|
||||||
final String tagName = (newIndex == -1) ? tagList.substring(index) : tagList.substring(index, newIndex);
|
|
||||||
description.addTag(tagName, true);
|
|
||||||
index = newIndex + 1;
|
|
||||||
} while (index != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.isFull()) {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (physicalFileName != fileName) {
|
|
||||||
BookDescriptionUtil.resetZipInfo(file);
|
|
||||||
}
|
|
||||||
BookDescriptionUtil.saveInfo(file);
|
|
||||||
}
|
|
||||||
ZLFile bookFile = new ZLFile(fileName);
|
|
||||||
|
|
||||||
FormatPlugin plugin = PluginCollection.instance().getPlugin(bookFile, false);
|
|
||||||
if ((plugin == null) || !plugin.readDescription(fileName, description)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description.myTitle.length() == 0) {
|
|
||||||
description.myTitle = bookFile.getName(true);
|
|
||||||
}
|
|
||||||
Author author = description.myAuthor;
|
|
||||||
if (author == null || author.DisplayName.length() == 0) {
|
|
||||||
description.myAuthor = new Author();
|
|
||||||
}
|
|
||||||
if (description.myEncoding.length() == 0) {
|
|
||||||
description.myEncoding = "auto";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BookInfo info = new BookInfo(fileName);
|
|
||||||
info.AuthorDisplayNameOption.setValue(description.myAuthor.DisplayName);
|
|
||||||
info.AuthorSortKeyOption.setValue(description.myAuthor.SortKey);
|
|
||||||
info.TitleOption.setValue(description.myTitle);
|
|
||||||
info.SeriesNameOption.setValue(description.mySeriesName);
|
|
||||||
info.NumberInSeriesOption.setValue(description.myNumberInSeries);
|
|
||||||
info.LanguageOption.setValue(description.myLanguage);
|
|
||||||
info.EncodingOption.setValue(description.myEncoding);
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BookDescription(String fileName) {
|
|
||||||
FileName = fileName;
|
|
||||||
myAuthor = null;
|
|
||||||
myNumberInSeries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Author getAuthor() {
|
|
||||||
return myAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return myTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSeriesName() {
|
|
||||||
return mySeriesName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberInSeries() {
|
|
||||||
return myNumberInSeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return myLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return myEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getTags() {
|
|
||||||
return Collections.unmodifiableList(myTags);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addTag(String tag, boolean check) {
|
|
||||||
if (check) {
|
|
||||||
tag = BookDescriptionUtil.removeWhiteSpacesFromTag(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag.length() > 0) && !myTags.contains(tag)) {
|
|
||||||
myTags.add(tag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveTags() {
|
|
||||||
saveTags(new ZLStringOption(FileName, "TagList", EMPTY));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveTags(ZLStringOption tagsOption) {
|
|
||||||
final ArrayList<String> tags = myTags;
|
|
||||||
if (tags.isEmpty()) {
|
|
||||||
tagsOption.setValue("");
|
|
||||||
} else {
|
|
||||||
final StringBuilder tagString = new StringBuilder();
|
|
||||||
tagString.append(tags.get(0));
|
|
||||||
final int len = tags.size();
|
|
||||||
for (int i = 1; i < len; ++i) {
|
|
||||||
tagString.append(",");
|
|
||||||
tagString.append(tags.get(i));
|
|
||||||
}
|
|
||||||
tagsOption.setValue(tagString.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BookInfo {
|
|
||||||
public final ZLStringOption AuthorDisplayNameOption;
|
|
||||||
public final ZLStringOption AuthorSortKeyOption;
|
|
||||||
public final ZLStringOption TitleOption;
|
|
||||||
public final ZLStringOption SeriesNameOption;
|
|
||||||
public final ZLIntegerRangeOption NumberInSeriesOption;
|
|
||||||
public final ZLStringOption LanguageOption;
|
|
||||||
public final ZLStringOption EncodingOption;
|
|
||||||
public final ZLStringOption TagsOption;
|
|
||||||
|
|
||||||
public BookInfo(String fileName) {
|
|
||||||
AuthorDisplayNameOption = new ZLStringOption(fileName, "AuthorDisplayName", EMPTY);
|
|
||||||
AuthorSortKeyOption = new ZLStringOption(fileName, "AuthorSortKey", EMPTY);
|
|
||||||
TitleOption = new ZLStringOption(fileName, "Title", EMPTY);
|
|
||||||
SeriesNameOption = new ZLStringOption(fileName, "Sequence", EMPTY);
|
|
||||||
NumberInSeriesOption = new ZLIntegerRangeOption(fileName, "Number in seq", 0, 100, 0);
|
|
||||||
LanguageOption = new ZLStringOption(fileName, "Language", UNKNOWN);
|
|
||||||
EncodingOption = new ZLStringOption(fileName, "Encoding", EMPTY);
|
|
||||||
TagsOption = new ZLStringOption(fileName, "TagList", EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFull() {
|
|
||||||
return
|
|
||||||
(AuthorDisplayNameOption.getValue().length() != 0) &&
|
|
||||||
(AuthorSortKeyOption.getValue().length() != 0) &&
|
|
||||||
(TitleOption.getValue().length() != 0) &&
|
|
||||||
(EncodingOption.getValue().length() != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
AuthorDisplayNameOption.setValue(EMPTY);
|
|
||||||
AuthorSortKeyOption.setValue(EMPTY);
|
|
||||||
TitleOption.setValue(EMPTY);
|
|
||||||
SeriesNameOption.setValue(EMPTY);
|
|
||||||
NumberInSeriesOption.setValue(0);
|
|
||||||
LanguageOption.setValue(UNKNOWN);
|
|
||||||
EncodingOption.setValue(EMPTY);
|
|
||||||
TagsOption.setValue(EMPTY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static public class WritableBookDescription {
|
|
||||||
private final BookDescription myDescription;
|
|
||||||
|
|
||||||
public WritableBookDescription(BookDescription description) {
|
|
||||||
myDescription = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAuthor(String name) {
|
|
||||||
addAuthor(name, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAuthor(String name, String sortKey) {
|
|
||||||
String strippedName = name;
|
|
||||||
strippedName.trim();
|
|
||||||
if (strippedName.length() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String strippedKey = sortKey;
|
|
||||||
strippedKey.trim();
|
|
||||||
if (strippedKey.length() == 0) {
|
|
||||||
int index = strippedName.lastIndexOf(' ');
|
|
||||||
if (index == -1) {
|
|
||||||
strippedKey = strippedName;
|
|
||||||
} else {
|
|
||||||
strippedKey = strippedName.substring(index + 1);
|
|
||||||
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
|
|
||||||
--index;
|
|
||||||
}
|
|
||||||
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Author author = new Author(strippedName, strippedKey);
|
|
||||||
|
|
||||||
if (myDescription.myAuthor == null) {
|
|
||||||
myDescription.myAuthor = author;
|
|
||||||
} else {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearAuthor() {
|
|
||||||
myDescription.myAuthor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Author getAuthor() {
|
|
||||||
return myDescription.getAuthor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return myDescription.myTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
myDescription.myTitle = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSeriesName() {
|
|
||||||
return myDescription.mySeriesName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSeriesName(String sequenceName) {
|
|
||||||
myDescription.mySeriesName = sequenceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberInSeries() {
|
|
||||||
return myDescription.myNumberInSeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumberInSeries(int numberInSeries) {
|
|
||||||
myDescription.myNumberInSeries = numberInSeries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName() {
|
|
||||||
return myDescription.FileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return myDescription.myLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLanguage(String language) {
|
|
||||||
myDescription.myLanguage = language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return myDescription.myEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEncoding(String encoding) {
|
|
||||||
myDescription.myEncoding = encoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTag(String tag, boolean check) {
|
|
||||||
if (myDescription.addTag(tag, check)) {
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeTag(String tag, boolean includeSubTags) {
|
|
||||||
final ArrayList<String> tags = myDescription.myTags;
|
|
||||||
if (includeSubTags) {
|
|
||||||
final String prefix = tag + '/';
|
|
||||||
boolean changed = false;
|
|
||||||
final int len = tags.size();
|
|
||||||
ArrayList toRemove = null;
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
String current = tags.get(i);
|
|
||||||
if (current.equals(tag) || current.startsWith(prefix)) {
|
|
||||||
if (toRemove == null) {
|
|
||||||
toRemove = new ArrayList();
|
|
||||||
}
|
|
||||||
toRemove.add(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toRemove != null) {
|
|
||||||
for (int i = toRemove.size() - 1; i >= 0; --i) {
|
|
||||||
tags.remove(((Integer)toRemove.get(i)).intValue());
|
|
||||||
}
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tags.remove(tag)) {
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renameTag(String from, String to, boolean includeSubTags) {
|
|
||||||
final ArrayList<String> tags = myDescription.myTags;
|
|
||||||
if (includeSubTags) {
|
|
||||||
final String prefix = from + '/';
|
|
||||||
final HashSet tagSet = new HashSet();
|
|
||||||
boolean changed = false;
|
|
||||||
final int len = tags.size();
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
final String value = tags.get(i);
|
|
||||||
if (from.equals(value)) {
|
|
||||||
tagSet.add(to);
|
|
||||||
changed = true;
|
|
||||||
} else if (value.startsWith(prefix)) {
|
|
||||||
tagSet.add(to + '/' + value.substring(prefix.length()));
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
tagSet.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
tags.clear();
|
|
||||||
tags.addAll(tagSet);
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tags.remove(from) && !tags.contains(to)) {
|
|
||||||
tags.add(to);
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cloneTag(String from, String to, boolean includeSubTags) {
|
|
||||||
final ArrayList<String> tags = myDescription.myTags;
|
|
||||||
if (includeSubTags) {
|
|
||||||
final String prefix = from + '/';
|
|
||||||
final HashSet tagSet = new HashSet();
|
|
||||||
final int len = tags.size();
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
final String value = tags.get(i);
|
|
||||||
if (value.equals(from)) {
|
|
||||||
tagSet.add(to);
|
|
||||||
} else if (value.startsWith(prefix)) {
|
|
||||||
tagSet.add(to + '/' + value.substring(prefix.length()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!tagSet.isEmpty()) {
|
|
||||||
tagSet.addAll(tags);
|
|
||||||
tags.clear();
|
|
||||||
tags.addAll(tagSet);
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tags.contains(from) && !tags.contains(to)) {
|
|
||||||
tags.add(to);
|
|
||||||
myDescription.saveTags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAllTags() {
|
|
||||||
myDescription.myTags.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -40,7 +40,6 @@ public interface ActionCode {
|
||||||
String DECREASE_FONT = "decreaseFont";
|
String DECREASE_FONT = "decreaseFont";
|
||||||
String TOGGLE_FULLSCREEN = "toggleFullscreen";
|
String TOGGLE_FULLSCREEN = "toggleFullscreen";
|
||||||
String FULLSCREEN_ON = "onFullscreen";
|
String FULLSCREEN_ON = "onFullscreen";
|
||||||
String SHOW_BOOK_INFO = "bookInfo";
|
|
||||||
String SHOW_HELP = "showHelp";
|
String SHOW_HELP = "showHelp";
|
||||||
String ROTATE_SCREEN = "rotate";
|
String ROTATE_SCREEN = "rotate";
|
||||||
String QUIT = "quit";
|
String QUIT = "quit";
|
||||||
|
|
|
@ -1,215 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.fbreader.fbreader;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.dialogs.*;
|
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
|
||||||
import org.geometerplus.zlibrary.core.language.ZLLanguageList;
|
|
||||||
import org.geometerplus.zlibrary.core.optionEntries.*;
|
|
||||||
|
|
||||||
import org.geometerplus.fbreader.collection.BookCollection;
|
|
||||||
import org.geometerplus.fbreader.description.*;
|
|
||||||
import org.geometerplus.fbreader.formats.*;
|
|
||||||
import org.geometerplus.fbreader.encodingOption.*;
|
|
||||||
import org.geometerplus.fbreader.encodingOption.EncodingEntry;
|
|
||||||
|
|
||||||
public class BookInfoDialog {
|
|
||||||
private final ZLOptionsDialog myDialog;
|
|
||||||
private final BookCollection myCollection;
|
|
||||||
// private final BookDescription.BookInfo myBookInfo;
|
|
||||||
// private FormatInfoPage myFormatInfoPage;
|
|
||||||
|
|
||||||
private AuthorDisplayNameEntry myAuthorDisplayNameEntry;
|
|
||||||
private AuthorSortKeyEntry myAuthorSortKeyEntry;
|
|
||||||
private ZLComboOptionEntry myEncodingSetEntry;
|
|
||||||
private ZLComboOptionEntry myEncodingEntry;
|
|
||||||
private ZLComboOptionEntry myLanguageEntry;
|
|
||||||
private SeriesTitleEntry mySeriesTitleEntry;
|
|
||||||
private ZLSpinOptionEntry myBookNumberEntry;
|
|
||||||
//private FormatInfoPage myFormatInfoPage;
|
|
||||||
|
|
||||||
public BookInfoDialog(String fileName, Runnable actionOnAccept) {
|
|
||||||
myCollection = BookCollection.Instance();
|
|
||||||
//myBookInfo = new BookDescription.BookInfo(fileName);
|
|
||||||
myDialog = ZLDialogManager.getInstance().createOptionsDialog("InfoDialog", actionOnAccept, null, false);
|
|
||||||
|
|
||||||
ZLDialogContent commonTab = myDialog.createTab("Common");
|
|
||||||
commonTab.addOption("file", new ZLStringInfoEntry(new ZLFile(fileName).getPath()));
|
|
||||||
//commonTab.addOption("title", myBookInfo.TitleOption);
|
|
||||||
|
|
||||||
myAuthorDisplayNameEntry = new AuthorDisplayNameEntry();
|
|
||||||
myAuthorSortKeyEntry = new AuthorSortKeyEntry();
|
|
||||||
//myEncodingEntry = new EncodingEntry(myBookInfo.EncodingOption);
|
|
||||||
myEncodingSetEntry =
|
|
||||||
(!"auto".equals(myEncodingEntry.initialValue())) ?
|
|
||||||
new EncodingSetEntry((EncodingEntry)myEncodingEntry) : null;
|
|
||||||
ArrayList/*<std::string>*/ languageCodes = ZLLanguageList.languageCodes();
|
|
||||||
languageCodes.add("de-traditional");
|
|
||||||
//myLanguageEntry = new ZLLanguageOptionEntry(myBookInfo.LanguageOption, languageCodes);
|
|
||||||
|
|
||||||
mySeriesTitleEntry = new SeriesTitleEntry();
|
|
||||||
//myBookNumberEntry = new ZLSimpleSpinOptionEntry(myBookInfo.NumberInSeriesOption, 1);
|
|
||||||
|
|
||||||
commonTab.addOption("authorDisplayName", myAuthorDisplayNameEntry);
|
|
||||||
commonTab.addOption("authorSortKey", myAuthorSortKeyEntry);
|
|
||||||
commonTab.addOption("language", myLanguageEntry);
|
|
||||||
if (myEncodingSetEntry != null) {
|
|
||||||
commonTab.addOption("encodingSet", myEncodingSetEntry);
|
|
||||||
}
|
|
||||||
commonTab.addOption("encoding", myEncodingEntry);
|
|
||||||
|
|
||||||
ZLDialogContent seriesTab = myDialog.createTab("Series");
|
|
||||||
seriesTab.addOption("seriesTitle", mySeriesTitleEntry);
|
|
||||||
seriesTab.addOption("bookNumber", myBookNumberEntry);
|
|
||||||
mySeriesTitleEntry.onValueEdited(mySeriesTitleEntry.initialValue());
|
|
||||||
|
|
||||||
ZLDialogContent tagsTab = myDialog.createTab("Tags");
|
|
||||||
//tagsTab.addOption("tags", myBookInfo.TagsOption);
|
|
||||||
|
|
||||||
//FormatPlugin plugin = PluginCollection.instance().getPlugin(new ZLFile(fileName), false);
|
|
||||||
//if (plugin != null) {
|
|
||||||
//myFormatInfoPage = plugin.createInfoPage(myDialog, fileName);
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZLOptionsDialog getDialog() {
|
|
||||||
return myDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AuthorSortKeyEntry extends ZLStringOptionEntry {
|
|
||||||
public String initialValue() {
|
|
||||||
Author currentAuthor = myAuthorDisplayNameEntry.myCurrentAuthor;
|
|
||||||
return //currentAuthor == null ?
|
|
||||||
//myBookInfo.AuthorSortKeyOption.getValue() :
|
|
||||||
currentAuthor.SortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAccept(String value) {
|
|
||||||
//myBookInfo.AuthorSortKeyOption.setValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AuthorDisplayNameEntry extends ZLComboOptionEntry {
|
|
||||||
private final ArrayList myValues = new ArrayList();
|
|
||||||
private Author myCurrentAuthor;
|
|
||||||
|
|
||||||
public AuthorDisplayNameEntry() {
|
|
||||||
super(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList getValues() {
|
|
||||||
if (myValues.size() == 0) {
|
|
||||||
final String initial = initialValue();
|
|
||||||
boolean addInitial = true;
|
|
||||||
/*
|
|
||||||
for (Author author : myCollection.authors()) {
|
|
||||||
final String name = author.DisplayName;
|
|
||||||
if (addInitial && name.equals(initial)) {
|
|
||||||
addInitial = false;
|
|
||||||
}
|
|
||||||
myValues.add(name);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (addInitial) {
|
|
||||||
myValues.add(initial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return myValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String initialValue() {
|
|
||||||
return "";//myBookInfo.AuthorDisplayNameOption.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAccept(String value) {
|
|
||||||
//myBookInfo.AuthorDisplayNameOption.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onValueSelected(int index) {
|
|
||||||
/*
|
|
||||||
final Collection<Author> authors = myCollection.authors();
|
|
||||||
if (index < authors.size()) {
|
|
||||||
myCurrentAuthor = new ArrayList<Author>(authors).get(index);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
myAuthorSortKeyEntry.resetView();
|
|
||||||
mySeriesTitleEntry.resetView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SeriesTitleEntry extends ZLComboOptionEntry {
|
|
||||||
private final ArrayList myValues = new ArrayList();
|
|
||||||
private Author myOriginalAuthor;
|
|
||||||
|
|
||||||
public SeriesTitleEntry() {
|
|
||||||
super(true);
|
|
||||||
final String authorName = "";//myBookInfo.AuthorDisplayNameOption.getValue();
|
|
||||||
final String authorKey = "";//myBookInfo.AuthorSortKeyOption.getValue();
|
|
||||||
/*
|
|
||||||
for (Author author : myCollection.authors()) {
|
|
||||||
if ((authorName != null && authorName.equals(author.DisplayName)) &&
|
|
||||||
(authorKey != null && authorKey.equals(author.SortKey))) {
|
|
||||||
myOriginalAuthor = author;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean useOnValueEdited() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onValueEdited(String value) {
|
|
||||||
myBookNumberEntry.setVisible(value != null && !value.equals(""));;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onValueSelected(int index) {
|
|
||||||
myBookNumberEntry.setVisible(index != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList getValues() {
|
|
||||||
myValues.clear();
|
|
||||||
HashSet valuesSet = new HashSet();
|
|
||||||
valuesSet.add(initialValue());
|
|
||||||
valuesSet.add("");
|
|
||||||
if (myOriginalAuthor != null) {
|
|
||||||
//myCollection.collectSeriesNames(myOriginalAuthor, valuesSet);
|
|
||||||
}
|
|
||||||
Author currentAuthor = myAuthorDisplayNameEntry.myCurrentAuthor;
|
|
||||||
if (currentAuthor != null && (currentAuthor != myOriginalAuthor)) {
|
|
||||||
//myCollection.collectSeriesNames(currentAuthor, valuesSet);
|
|
||||||
}
|
|
||||||
myValues.addAll(valuesSet);
|
|
||||||
return myValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String initialValue() {
|
|
||||||
return "";//myBookInfo.SeriesNameOption.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAccept(String value) {
|
|
||||||
//myBookInfo.SeriesNameOption.setValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,7 +38,7 @@ import org.geometerplus.zlibrary.text.hyphenation.ZLTextHyphenator;
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
import org.geometerplus.fbreader.bookmodel.BookModel;
|
||||||
import org.geometerplus.fbreader.collection.BookCollection;
|
import org.geometerplus.fbreader.collection.BookCollection;
|
||||||
import org.geometerplus.fbreader.collection.RecentBooks;
|
import org.geometerplus.fbreader.collection.RecentBooks;
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
|
|
||||||
public final class FBReader extends ZLApplication {
|
public final class FBReader extends ZLApplication {
|
||||||
static interface ViewMode {
|
static interface ViewMode {
|
||||||
|
@ -108,7 +108,6 @@ public final class FBReader extends ZLApplication {
|
||||||
addAction(ActionCode.SHOW_LIBRARY, new ShowLibrary(this));
|
addAction(ActionCode.SHOW_LIBRARY, new ShowLibrary(this));
|
||||||
addAction(ActionCode.SHOW_OPTIONS, new ShowOptionsDialogAction(this));
|
addAction(ActionCode.SHOW_OPTIONS, new ShowOptionsDialogAction(this));
|
||||||
addAction(ActionCode.SHOW_CONTENTS, new ShowTOCAction(this));
|
addAction(ActionCode.SHOW_CONTENTS, new ShowTOCAction(this));
|
||||||
addAction(ActionCode.SHOW_BOOK_INFO, new ShowBookInfoDialogAction(this));
|
|
||||||
|
|
||||||
addAction(ActionCode.SEARCH, new SearchAction(this));
|
addAction(ActionCode.SEARCH, new SearchAction(this));
|
||||||
addAction(ActionCode.FIND_NEXT, new FindNextAction(this));
|
addAction(ActionCode.FIND_NEXT, new FindNextAction(this));
|
||||||
|
@ -239,13 +238,10 @@ public final class FBReader extends ZLApplication {
|
||||||
BookTextView.setModels(null, "");
|
BookTextView.setModels(null, "");
|
||||||
|
|
||||||
Model = null;
|
Model = null;
|
||||||
//android.os.Debug.startMethodTracing("/data/anr/loading");
|
|
||||||
Model = new BookModel(description);
|
Model = new BookModel(description);
|
||||||
//android.os.Debug.stopMethodTracing();
|
|
||||||
final String fileName = description.FileName;
|
final String fileName = description.FileName;
|
||||||
myBookNameOption.setValue(fileName);
|
myBookNameOption.setValue(fileName);
|
||||||
ZLTextHyphenator.getInstance().load(description.getLanguage());
|
ZLTextHyphenator.getInstance().load(description.getLanguage());
|
||||||
// BookTextView.setModel(Model.BookTextModel, fileName);
|
|
||||||
BookTextView.setModels(Model.getBookTextModels(), fileName);
|
BookTextView.setModels(Model.getBookTextModels(), fileName);
|
||||||
BookTextView.setCaption(description.getTitle());
|
BookTextView.setCaption(description.getTitle());
|
||||||
FootnoteView.setModel(null);
|
FootnoteView.setModel(null);
|
||||||
|
@ -268,9 +264,7 @@ public final class FBReader extends ZLApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
//final long start = System.currentTimeMillis();
|
|
||||||
openBookInternal(myDescription);
|
openBookInternal(myDescription);
|
||||||
//android.util.Log.w("openBook", "" + (System.currentTimeMillis() - start));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2009 Geometer Plus <contact@geometerplus.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.fbreader.fbreader;
|
|
||||||
|
|
||||||
import org.geometerplus.fbreader.collection.BookCollection;
|
|
||||||
|
|
||||||
class ShowBookInfoDialogAction extends FBAction {
|
|
||||||
ShowBookInfoDialogAction(FBReader fbreader) {
|
|
||||||
super(fbreader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVisible() {
|
|
||||||
return Reader.getMode() == FBReader.ViewMode.BOOK_TEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
final String fileName = Reader.BookTextView.getFileName();
|
|
||||||
Runnable action = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
Reader.openFile(fileName);
|
|
||||||
Reader.refreshWindow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
new BookInfoDialog(fileName, action).getDialog().run();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.fbreader;
|
package org.geometerplus.fbreader.fbreader;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
|
|
||||||
class ShowHelpAction extends FBAction {
|
class ShowHelpAction extends FBAction {
|
||||||
ShowHelpAction(FBReader fbreader) {
|
ShowHelpAction(FBReader fbreader) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ShowTOCAction extends FBAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return Reader.Model.ContentsTree.hasChildren();
|
return Reader.Model.TOCTree.hasChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -23,8 +23,7 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
import org.geometerplus.fbreader.bookmodel.BookModel;
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
|
|
||||||
import org.geometerplus.zlibrary.core.dialogs.ZLOptionsDialog;
|
import org.geometerplus.zlibrary.core.dialogs.ZLOptionsDialog;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
import org.geometerplus.zlibrary.core.language.ZLLanguageDetector;
|
import org.geometerplus.zlibrary.core.language.ZLLanguageDetector;
|
||||||
|
@ -72,8 +71,8 @@ public abstract class FormatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new WritableBookDescription(description).setEncoding(encoding);
|
description.setEncoding(encoding);
|
||||||
new WritableBookDescription(description).setLanguage(language);
|
description.setLanguage(language);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Last working version
|
//Last working version
|
||||||
|
@ -84,24 +83,24 @@ public abstract class FormatPlugin {
|
||||||
if (encoding == "unknown") {
|
if (encoding == "unknown") {
|
||||||
encoding = "windows-1252";
|
encoding = "windows-1252";
|
||||||
}
|
}
|
||||||
new WritableBookDescription(description).setEncoding(encoding);
|
description.setEncoding(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (description.getLanguage() == "") {
|
if (description.getLanguage() == "") {
|
||||||
if ((encoding.equals("US-ASCII")) ||
|
if ((encoding.equals("US-ASCII")) ||
|
||||||
(encoding.equals("ISO-8859-1"))) {
|
(encoding.equals("ISO-8859-1"))) {
|
||||||
new WritableBookDescription(description).setLanguage("en");
|
description.setLanguage("en");
|
||||||
} else if ((description.getEncoding().equals("KOI8-R")) ||
|
} else if ((description.getEncoding().equals("KOI8-R")) ||
|
||||||
(encoding.equals("windows-1251")) ||
|
(encoding.equals("windows-1251")) ||
|
||||||
(encoding.equals("ISO-8859-5")) ||
|
(encoding.equals("ISO-8859-5")) ||
|
||||||
(encoding.equals("IBM866"))) {
|
(encoding.equals("IBM866"))) {
|
||||||
new WritableBookDescription(description).setLanguage("ru");
|
description.setLanguage("ru");
|
||||||
} /*else if (
|
} /*else if (
|
||||||
(PluginCollection.instance().DefaultLanguageOption.getValue() == EncodingDetector.Language.CZECH) &&
|
(PluginCollection.instance().DefaultLanguageOption.getValue() == EncodingDetector.Language.CZECH) &&
|
||||||
((encoding == "windows-1250") ||
|
((encoding == "windows-1250") ||
|
||||||
(encoding == "ISO-8859-2") ||
|
(encoding == "ISO-8859-2") ||
|
||||||
(encoding == "IBM852"))) {
|
(encoding == "IBM852"))) {
|
||||||
new WritableBookDescription(description).setLanguage("cs");
|
description.setLanguage("cs");
|
||||||
}*/
|
}*/
|
||||||
/*}
|
/*}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ import java.util.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.xml.*;
|
import org.geometerplus.zlibrary.core.xml.*;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
|
import org.geometerplus.fbreader.collection.Tag;
|
||||||
|
|
||||||
public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
private final static int READ_NOTHING = 0;
|
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_LANGUAGE = 7;
|
||||||
private final static int READ_GENRE = 8;
|
private final static int READ_GENRE = 8;
|
||||||
|
|
||||||
private WritableBookDescription myDescription;
|
private final BookDescription myDescription;
|
||||||
private int myReadState = READ_NOTHING;
|
private int myReadState = READ_NOTHING;
|
||||||
|
|
||||||
private final String[] myAuthorNames = new String[3];
|
private final String[] myAuthorNames = new String[3];
|
||||||
private final StringBuilder myGenreBuffer = new StringBuilder();
|
private final StringBuilder myBuffer = new StringBuilder();
|
||||||
|
|
||||||
public FB2DescriptionReader(BookDescription description) {
|
public FB2DescriptionReader(BookDescription description) {
|
||||||
myDescription = new WritableBookDescription(description);
|
myDescription = description;
|
||||||
myDescription.clearAuthor();
|
myDescription.setTitle(null);
|
||||||
myDescription.setTitle("");
|
myDescription.setLanguage(null);
|
||||||
myDescription.setLanguage("");
|
|
||||||
myDescription.removeAllTags();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean dontCacheAttributeValues() {
|
public boolean dontCacheAttributeValues() {
|
||||||
|
@ -60,7 +58,7 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
myAuthorNames[0] = "";
|
myAuthorNames[0] = "";
|
||||||
myAuthorNames[1] = "";
|
myAuthorNames[1] = "";
|
||||||
myAuthorNames[2] = "";
|
myAuthorNames[2] = "";
|
||||||
myGenreBuffer.delete(0, myGenreBuffer.length());
|
myBuffer.delete(0, myBuffer.length());
|
||||||
return readDocument(fileName);
|
return readDocument(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,11 +108,11 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
if (myReadState == READ_SOMETHING) {
|
if (myReadState == READ_SOMETHING) {
|
||||||
String name = attributes.getValue("name");
|
String name = attributes.getValue("name");
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
String sequenceName = name;
|
name.trim();
|
||||||
sequenceName.trim();
|
if (name.length() != 0) {
|
||||||
myDescription.setSeriesName(sequenceName);
|
String index = attributes.getValue("number");
|
||||||
String number = attributes.getValue("number");
|
myDescription.setSeriesInfo(name, (index != null) ? Integer.parseInt(index) : 0);
|
||||||
myDescription.setNumberInSeries((number != null) ? Integer.parseInt(number) : 0);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -129,22 +127,21 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
break;
|
break;
|
||||||
case FB2Tag.BOOK_TITLE:
|
case FB2Tag.BOOK_TITLE:
|
||||||
if (myReadState == READ_TITLE) {
|
if (myReadState == READ_TITLE) {
|
||||||
|
myDescription.setTitle(myBuffer.toString().trim());
|
||||||
myReadState = READ_SOMETHING;
|
myReadState = READ_SOMETHING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FB2Tag.GENRE:
|
case FB2Tag.GENRE:
|
||||||
if (myReadState == READ_GENRE) {
|
if (myReadState == READ_GENRE) {
|
||||||
final String genre = myGenreBuffer.toString().trim();
|
final String genre = myBuffer.toString().trim();
|
||||||
myGenreBuffer.delete(0, myGenreBuffer.length());
|
|
||||||
if (genre.length() > 0) {
|
if (genre.length() > 0) {
|
||||||
final ArrayList tags = FB2TagManager.humanReadableTags(genre);
|
final ArrayList<Tag> tags = FB2TagManager.humanReadableTags(genre);
|
||||||
if (tags != null) {
|
if (tags != null) {
|
||||||
final int len = tags.size();
|
for (Tag t : tags) {
|
||||||
for (int i = 0; i < len; ++i) {
|
myDescription.addTag(t);
|
||||||
myDescription.addTag((String)tags.get(i), false);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
myDescription.addTag(genre, true);
|
myDescription.addTag(genre);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
myReadState = READ_SOMETHING;
|
myReadState = READ_SOMETHING;
|
||||||
|
@ -173,6 +170,7 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
break;
|
break;
|
||||||
case FB2Tag.LANG:
|
case FB2Tag.LANG:
|
||||||
if (myReadState == READ_LANGUAGE) {
|
if (myReadState == READ_LANGUAGE) {
|
||||||
|
myDescription.setLanguage(myBuffer.toString().trim());
|
||||||
myReadState = READ_SOMETHING;
|
myReadState = READ_SOMETHING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -194,17 +192,12 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
myBuffer.delete(0, myBuffer.length());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void characterDataHandler(char[] data, int start, int length) {
|
public void characterDataHandler(char[] data, int start, int length) {
|
||||||
switch (myReadState) {
|
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:
|
case READ_AUTHOR_NAME_0:
|
||||||
myAuthorNames[0] += new String(data, start, length);
|
myAuthorNames[0] += new String(data, start, length);
|
||||||
break;
|
break;
|
||||||
|
@ -214,8 +207,10 @@ public class FB2DescriptionReader extends ZLXMLReaderAdapter {
|
||||||
case READ_AUTHOR_NAME_2:
|
case READ_AUTHOR_NAME_2:
|
||||||
myAuthorNames[2] += new String(data, start, length);
|
myAuthorNames[2] += new String(data, start, length);
|
||||||
break;
|
break;
|
||||||
|
case READ_TITLE:
|
||||||
|
case READ_LANGUAGE:
|
||||||
case READ_GENRE:
|
case READ_GENRE:
|
||||||
myGenreBuffer.append(data, start, length);
|
myBuffer.append(data, start, length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
package org.geometerplus.fbreader.formats.fb2;
|
package org.geometerplus.fbreader.formats.fb2;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
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.fbreader.formats.FormatPlugin;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,18 @@ import org.geometerplus.zlibrary.core.util.*;
|
||||||
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
||||||
import org.geometerplus.zlibrary.core.xml.*;
|
import org.geometerplus.zlibrary.core.xml.*;
|
||||||
|
|
||||||
abstract class FB2TagManager {
|
import org.geometerplus.fbreader.collection.Tag;
|
||||||
private static final HashMap ourMap = new HashMap();
|
|
||||||
|
|
||||||
static ArrayList humanReadableTags(String id) {
|
abstract class FB2TagManager {
|
||||||
|
private static final HashMap<String,ArrayList<Tag>> ourMap = new HashMap<String,ArrayList<Tag>>();
|
||||||
|
|
||||||
|
static ArrayList<Tag> humanReadableTags(String id) {
|
||||||
if (ourMap.isEmpty()) {
|
if (ourMap.isEmpty()) {
|
||||||
new FB2TagInfoReader().read(
|
new FB2TagInfoReader().read(
|
||||||
ZLibrary.JAR_DATA_PREFIX + "data/formats/fb2/fb2genres.xml"
|
ZLibrary.JAR_DATA_PREFIX + "data/formats/fb2/fb2genres.xml"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (ArrayList)ourMap.get(id);
|
return ourMap.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FB2TagManager() {
|
private FB2TagManager() {
|
||||||
|
@ -42,9 +44,9 @@ abstract class FB2TagManager {
|
||||||
|
|
||||||
private static class FB2TagInfoReader extends ZLXMLReaderAdapter {
|
private static class FB2TagInfoReader extends ZLXMLReaderAdapter {
|
||||||
private final String myLanguage;
|
private final String myLanguage;
|
||||||
private String myCategoryName;
|
private Tag myCategoryTag;
|
||||||
private String mySubCategoryName;
|
private Tag mySubCategoryTag;
|
||||||
private final ArrayList myGenreIds = new ArrayList();
|
private final ArrayList<String> myGenreIds = new ArrayList<String>();
|
||||||
|
|
||||||
FB2TagInfoReader() {
|
FB2TagInfoReader() {
|
||||||
final String language = Locale.getDefault().getLanguage();
|
final String language = Locale.getDefault().getLanguage();
|
||||||
|
@ -59,17 +61,11 @@ abstract class FB2TagManager {
|
||||||
}
|
}
|
||||||
} else if (tag == "root-descr") {
|
} else if (tag == "root-descr") {
|
||||||
if (myLanguage == attributes.getValue("lang")) {
|
if (myLanguage == attributes.getValue("lang")) {
|
||||||
final String name = attributes.getValue("genre-title");
|
myCategoryTag = Tag.getTag(null, attributes.getValue("genre-title"));
|
||||||
if (name != null) {
|
|
||||||
myCategoryName = name.trim();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (tag == "genre-descr") {
|
} else if (tag == "genre-descr") {
|
||||||
if (myLanguage == attributes.getValue("lang")) {
|
if (myLanguage == attributes.getValue("lang")) {
|
||||||
final String name = attributes.getValue("title");
|
mySubCategoryTag = Tag.getTag(myCategoryTag, attributes.getValue("title"));
|
||||||
if (name != null) {
|
|
||||||
mySubCategoryName = name.trim();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -77,24 +73,21 @@ abstract class FB2TagManager {
|
||||||
|
|
||||||
public boolean endElementHandler(String tag) {
|
public boolean endElementHandler(String tag) {
|
||||||
if (tag == "genre") {
|
if (tag == "genre") {
|
||||||
myCategoryName = null;
|
myCategoryTag = null;
|
||||||
mySubCategoryName = null;
|
mySubCategoryTag = null;
|
||||||
myGenreIds.clear();
|
myGenreIds.clear();
|
||||||
} else if (tag == "subgenre") {
|
} else if (tag == "subgenre") {
|
||||||
if ((myCategoryName != null) && (mySubCategoryName != null)) {
|
if (mySubCategoryTag != null) {
|
||||||
final String fullTagName = myCategoryName + '/' + mySubCategoryName;
|
for (String id : myGenreIds) {
|
||||||
final int len = myGenreIds.size();
|
ArrayList<Tag> list = ourMap.get(id);
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
final Object id = myGenreIds.get(i);
|
|
||||||
ArrayList list = (ArrayList)ourMap.get(id);
|
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList();
|
list = new ArrayList<Tag>();
|
||||||
ourMap.put(id, list);
|
ourMap.put(id, list);
|
||||||
}
|
}
|
||||||
list.add(fullTagName);
|
list.add(mySubCategoryTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mySubCategoryName = null;
|
mySubCategoryTag = null;
|
||||||
myGenreIds.clear();
|
myGenreIds.clear();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,21 +19,19 @@
|
||||||
|
|
||||||
package org.geometerplus.fbreader.formats.html;
|
package org.geometerplus.fbreader.formats.html;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
|
|
||||||
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
||||||
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessor;
|
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessor;
|
||||||
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessorFactory;
|
import org.geometerplus.zlibrary.core.xml.ZLXMLProcessorFactory;
|
||||||
import org.geometerplus.zlibrary.core.xml.ZLXMLReaderAdapter;
|
import org.geometerplus.zlibrary.core.xml.ZLXMLReaderAdapter;
|
||||||
|
|
||||||
public class HtmlDescriptionReader extends ZLXMLReaderAdapter {
|
public class HtmlDescriptionReader extends ZLXMLReaderAdapter {
|
||||||
|
private final BookDescription myDescription;
|
||||||
private WritableBookDescription myDescription;
|
|
||||||
|
|
||||||
private boolean myReadTitle;
|
private boolean myReadTitle;
|
||||||
|
|
||||||
public HtmlDescriptionReader(BookDescription description) {
|
public HtmlDescriptionReader(BookDescription description) {
|
||||||
myDescription = new WritableBookDescription(description);
|
myDescription = description;
|
||||||
myDescription.setTitle("");
|
myDescription.setTitle("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
package org.geometerplus.fbreader.formats.html;
|
package org.geometerplus.fbreader.formats.html;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
import org.geometerplus.fbreader.bookmodel.BookModel;
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.description.BookDescription.WritableBookDescription;
|
|
||||||
import org.geometerplus.fbreader.formats.FormatPlugin;
|
import org.geometerplus.fbreader.formats.FormatPlugin;
|
||||||
import org.geometerplus.fbreader.formats.fb2.FB2DescriptionReader;
|
import org.geometerplus.fbreader.formats.fb2.FB2DescriptionReader;
|
||||||
import org.geometerplus.fbreader.formats.fb2.FB2Reader;
|
import org.geometerplus.fbreader.formats.fb2.FB2Reader;
|
||||||
|
|
|
@ -22,11 +22,11 @@ package org.geometerplus.fbreader.formats.oeb;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.xml.*;
|
import org.geometerplus.zlibrary.core.xml.*;
|
||||||
import org.geometerplus.fbreader.description.BookDescription;
|
import org.geometerplus.fbreader.collection.BookDescription;
|
||||||
import org.geometerplus.fbreader.constants.XMLNamespace;
|
import org.geometerplus.fbreader.constants.XMLNamespace;
|
||||||
|
|
||||||
class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
|
class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
|
||||||
private final BookDescription.WritableBookDescription myDescription;
|
private final BookDescription myDescription;
|
||||||
|
|
||||||
private String myDCMetadataTag = "dc-metadata";
|
private String myDCMetadataTag = "dc-metadata";
|
||||||
private String myMetadataTag = "metadata";
|
private String myMetadataTag = "metadata";
|
||||||
|
@ -36,14 +36,13 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
|
||||||
private String mySubjectTag;
|
private String mySubjectTag;
|
||||||
private String myLanguageTag;
|
private String myLanguageTag;
|
||||||
|
|
||||||
private final ArrayList myAuthorList = new ArrayList();
|
private final ArrayList<String> myAuthorList = new ArrayList<String>();
|
||||||
private final ArrayList myAuthorList2 = new ArrayList();
|
private final ArrayList<String> myAuthorList2 = new ArrayList<String>();
|
||||||
|
|
||||||
OEBDescriptionReader(BookDescription description) {
|
OEBDescriptionReader(BookDescription description) {
|
||||||
myDescription = new BookDescription.WritableBookDescription(description);
|
myDescription = description;
|
||||||
myDescription.clearAuthor();
|
myDescription.setTitle(null);
|
||||||
myDescription.setTitle("");
|
myDescription.setLanguage(null);
|
||||||
myDescription.removeAllTags();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean readDescription(String fileName) {
|
boolean readDescription(String fileName) {
|
||||||
|
@ -56,10 +55,15 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayList authors = myAuthorList.isEmpty() ? myAuthorList2 : myAuthorList;
|
final ArrayList<String> authors = myAuthorList.isEmpty() ? myAuthorList2 : myAuthorList;
|
||||||
final int len = authors.size();
|
for (String a : authors) {
|
||||||
for (int i = 0; i < len; ++i) {
|
final int index = a.indexOf(',');
|
||||||
myDescription.addAuthor((String)authors.get(i));
|
if (index >= 0) {
|
||||||
|
a = a.substring(index + 1).trim() + ' ' + a.substring(0, index).trim();
|
||||||
|
} else {
|
||||||
|
a = a.trim();
|
||||||
|
}
|
||||||
|
myDescription.addAuthor(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -158,7 +162,7 @@ class OEBDescriptionReader extends ZLXMLReaderAdapter implements XMLNamespace {
|
||||||
myAuthorList2.add(bufferContent);
|
myAuthorList2.add(bufferContent);
|
||||||
break;
|
break;
|
||||||
case READ_SUBJECT:
|
case READ_SUBJECT:
|
||||||
myDescription.addTag(bufferContent, true);
|
myDescription.addTag(bufferContent);
|
||||||
break;
|
break;
|
||||||
case READ_LANGUAGE:
|
case READ_LANGUAGE:
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.oeb;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
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.fbreader.formats.FormatPlugin;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.*;
|
import org.geometerplus.zlibrary.core.filesystem.*;
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ public class OEBPlugin extends FormatPlugin {
|
||||||
|
|
||||||
public boolean readDescription(String path, BookDescription description) {
|
public boolean readDescription(String path, BookDescription description) {
|
||||||
path = getOpfFileName(path);
|
path = getOpfFileName(path);
|
||||||
System.err.println("path = " + path);
|
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.pdb;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
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.FormatPlugin;
|
||||||
import org.geometerplus.fbreader.formats.plucker.PluckerTextStream;
|
import org.geometerplus.fbreader.formats.plucker.PluckerTextStream;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats.plucker;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.bookmodel.BookModel;
|
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.PdbPlugin;
|
||||||
import org.geometerplus.fbreader.formats.pdb.PdbStream;
|
import org.geometerplus.fbreader.formats.pdb.PdbStream;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
|
|
|
@ -127,7 +127,6 @@ public class KeyBindingsPage {
|
||||||
|
|
||||||
// dialogs
|
// dialogs
|
||||||
addAction(ActionCode.SHOW_OPTIONS);
|
addAction(ActionCode.SHOW_OPTIONS);
|
||||||
addAction(ActionCode.SHOW_BOOK_INFO);
|
|
||||||
|
|
||||||
// quit
|
// quit
|
||||||
addAction(ActionCode.CANCEL);
|
addAction(ActionCode.CANCEL);
|
||||||
|
|
|
@ -401,7 +401,6 @@ public abstract class ZLTextViewImpl extends ZLTextView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void paint() {
|
public synchronized void paint() {
|
||||||
//android.os.Debug.startMethodTracing("/tmp/paint");
|
|
||||||
myTextElementMap.clear();
|
myTextElementMap.clear();
|
||||||
myTreeNodeMap.clear();
|
myTreeNodeMap.clear();
|
||||||
|
|
||||||
|
@ -445,7 +444,6 @@ public abstract class ZLTextViewImpl extends ZLTextView {
|
||||||
for (int i = 0; i < lineInfosSize; ++i) {
|
for (int i = 0; i < lineInfosSize; ++i) {
|
||||||
drawTextLine(context, lineInfos.getInfo(i), labels[i], labels[i + 1]);
|
drawTextLine(context, lineInfos.getInfo(i), labels[i], labels[i + 1]);
|
||||||
}
|
}
|
||||||
//android.os.Debug.stopMethodTracing();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int sizeOfTextBeforeCursor(ZLTextWordCursor wordCursor) {
|
private int sizeOfTextBeforeCursor(ZLTextWordCursor wordCursor) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue