From 3991c59ce1dd6eb6c94bbe4030996bf0f0558145 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Fri, 3 May 2013 01:15:00 +0400 Subject: [PATCH] hightlighting style from db --- TODO.highlighting | 2 +- .../libraryService/BookCollectionShadow.java | 22 ++++++ .../libraryService/LibraryInterface.aidl | 3 + .../libraryService/LibraryService.java | 8 +++ .../libraryService/SQLiteBooksDatabase.java | 18 ++++- .../fbreader/book/AbstractSerializer.java | 3 + .../fbreader/book/BookCollection.java | 21 ++++++ .../fbreader/book/BooksDatabase.java | 6 ++ .../fbreader/book/HighlightingStyle.java | 35 ++++++++++ .../fbreader/book/IBookCollection.java | 3 + .../fbreader/book/SerializerUtil.java | 43 +++++++++--- .../fbreader/book/XMLSerializer.java | 68 +++++++++++++++++++ .../fbreader/BookmarkHighlighting.java | 12 +++- .../fbreader/fbreader/FBReaderApp.java | 2 +- .../zlibrary/core/util/ZLColor.java | 11 +++ 15 files changed, 241 insertions(+), 16 deletions(-) create mode 100644 src/org/geometerplus/fbreader/book/HighlightingStyle.java diff --git a/TODO.highlighting b/TODO.highlighting index 3454c4d88..9aaebd2b6 100644 --- a/TODO.highlighting +++ b/TODO.highlighting @@ -2,7 +2,7 @@ DONE highlight bookmarks * show highlights in footnote view * don't draw all bookmarks, filter by position * restore end position for old bookmarks -* save bookmark style +DONE save bookmark style * change style (color) for bookmarks: user interface DONE watch bookmark changes DONE fix selection bookmark range diff --git a/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java b/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java index d002fcf84..5ec7f4daf 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java +++ b/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java @@ -416,6 +416,28 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv } } + public HighlightingStyle getHighlightingStyle(int styleId) { + if (myInterface == null) { + return null; + } + try { + return SerializerUtil.deserializeStyle(myInterface.getHighlightingStyle(styleId)); + } catch (RemoteException e) { + return null; + } + } + + public List highlightingStyles() { + if (myInterface == null) { + return Collections.emptyList(); + } + try { + return SerializerUtil.deserializeStyleList(myInterface.highlightingStyles()); + } catch (RemoteException e) { + return Collections.emptyList(); + } + } + // method from ServiceConnection interface public synchronized void onServiceConnected(ComponentName name, IBinder service) { myInterface = LibraryInterface.Stub.asInterface(service); diff --git a/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl b/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl index e23b4dd34..40f83b69d 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl +++ b/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl @@ -44,4 +44,7 @@ interface LibraryInterface { List bookmarks(in String query); String saveBookmark(in String bookmark); void deleteBookmark(in String bookmark); + + String getHighlightingStyle(in int styleId); + List highlightingStyles(); } diff --git a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java index 0c31a52f3..713287a52 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java +++ b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java @@ -261,6 +261,14 @@ public class LibraryService extends Service { public void deleteBookmark(String serialized) { myCollection.deleteBookmark(SerializerUtil.deserializeBookmark(serialized)); } + + public String getHighlightingStyle(int styleId) { + return SerializerUtil.serialize(myCollection.getHighlightingStyle(styleId)); + } + + public List highlightingStyles() { + return SerializerUtil.serializeStyleList(myCollection.highlightingStyles()); + } } private volatile LibraryImplementation myLibrary; diff --git a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java index fbf92fb60..94eaad3a4 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java +++ b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java @@ -878,6 +878,18 @@ final class SQLiteBooksDatabase extends BooksDatabase { return list; } + @Override + protected List loadStyles() { + final LinkedList list = new LinkedList(); + final String sql = "SELECT style_id,bg_color FROM HighlightingStyle"; + final Cursor cursor = myDatabase.rawQuery(sql, null); + while (cursor.moveToNext()) { + list.add(createStyle((int)cursor.getLong(0), (int)cursor.getLong(1))); + } + cursor.close(); + return list; + } + private SQLiteStatement myInsertBookmarkStatement; private SQLiteStatement myUpdateBookmarkStatement; @Override @@ -1397,9 +1409,9 @@ final class SQLiteBooksDatabase extends BooksDatabase { "style_id INTEGER PRIMARY KEY," + "name TEXT," + "bg_color INTEGER NOT NULL)"); - myDatabase.execSQL("INSERT INTO HighlightingStyle (style_id, name, bg_color) VALUES (1, 'default', 136*256*256 + 138*256 + 133)"); // #888a85 - myDatabase.execSQL("INSERT INTO HighlightingStyle (style_id, name, bg_color) VALUES (2, 'orange', 245*256*256 + 121*256 + 0)"); // #f57900 - myDatabase.execSQL("INSERT INTO HighlightingStyle (style_id, name, bg_color) VALUES (3, 'blue', 114*160*256 + 159*256 + 207)"); // #729fcf + myDatabase.execSQL("INSERT OR REPLACE INTO HighlightingStyle (style_id, name, bg_color) VALUES (1, 'default', 136*256*256 + 138*256 + 133)"); // #888a85 + myDatabase.execSQL("INSERT OR REPLACE INTO HighlightingStyle (style_id, name, bg_color) VALUES (2, 'orange', 245*256*256 + 121*256 + 0)"); // #f57900 + myDatabase.execSQL("INSERT OR REPLACE INTO HighlightingStyle (style_id, name, bg_color) VALUES (3, 'blue', 114*160*256 + 159*256 + 207)"); // #729fcf myDatabase.execSQL("ALTER TABLE Bookmarks ADD COLUMN style_id INTEGER NOT NULL REFERENCES HighlightingStyle(style_id) DEFAULT 1"); myDatabase.execSQL("UPDATE Bookmarks SET end_paragraph = LENGTH(bookmark_text)"); } diff --git a/src/org/geometerplus/fbreader/book/AbstractSerializer.java b/src/org/geometerplus/fbreader/book/AbstractSerializer.java index 8266657a3..b9e8c18e5 100644 --- a/src/org/geometerplus/fbreader/book/AbstractSerializer.java +++ b/src/org/geometerplus/fbreader/book/AbstractSerializer.java @@ -31,4 +31,7 @@ abstract class AbstractSerializer { public abstract String serialize(Bookmark bookmark); public abstract Bookmark deserializeBookmark(String data); + + public abstract String serialize(HighlightingStyle style); + public abstract HighlightingStyle deserializeStyle(String data); } diff --git a/src/org/geometerplus/fbreader/book/BookCollection.java b/src/org/geometerplus/fbreader/book/BookCollection.java index df23582d9..0a90e086f 100644 --- a/src/org/geometerplus/fbreader/book/BookCollection.java +++ b/src/org/geometerplus/fbreader/book/BookCollection.java @@ -43,6 +43,9 @@ public class BookCollection extends AbstractBookCollection { private volatile Status myStatus = Status.NotStarted; + private final Map myStyles = + Collections.synchronizedMap(new TreeMap()); + public BookCollection(BooksDatabase db, List bookDirectories) { myDatabase = db; BookDirectories = Collections.unmodifiableList(new ArrayList(bookDirectories)); @@ -653,4 +656,22 @@ public class BookCollection extends AbstractBookCollection { public void markHyperlinkAsVisited(Book book, String linkId) { book.markHyperlinkAsVisited(myDatabase, linkId); } + + private synchronized void initStylesTable() { + if (myStyles.isEmpty()) { + for (HighlightingStyle style : myDatabase.loadStyles()) { + myStyles.put(style.Id, style); + } + } + } + + public HighlightingStyle getHighlightingStyle(int styleId) { + initStylesTable(); + return myStyles.get(styleId); + } + + public List highlightingStyles() { + initStylesTable(); + return new ArrayList(myStyles.values()); + } } diff --git a/src/org/geometerplus/fbreader/book/BooksDatabase.java b/src/org/geometerplus/fbreader/book/BooksDatabase.java index e009c237d..a33aabf0e 100644 --- a/src/org/geometerplus/fbreader/book/BooksDatabase.java +++ b/src/org/geometerplus/fbreader/book/BooksDatabase.java @@ -22,6 +22,7 @@ package org.geometerplus.fbreader.book; import java.util.*; import org.geometerplus.zlibrary.core.filesystem.ZLFile; +import org.geometerplus.zlibrary.core.util.ZLColor; import org.geometerplus.zlibrary.text.view.ZLTextPosition; @@ -110,6 +111,11 @@ public abstract class BooksDatabase { protected abstract long saveBookmark(Bookmark bookmark); protected abstract void deleteBookmark(Bookmark bookmark); + protected HighlightingStyle createStyle(int id, int color) { + return new HighlightingStyle(id, new ZLColor(color)); + } + protected abstract List loadStyles(); + protected abstract ZLTextPosition getStoredPosition(long bookId); protected abstract void storePosition(long bookId, ZLTextPosition position); diff --git a/src/org/geometerplus/fbreader/book/HighlightingStyle.java b/src/org/geometerplus/fbreader/book/HighlightingStyle.java new file mode 100644 index 000000000..c6c36689b --- /dev/null +++ b/src/org/geometerplus/fbreader/book/HighlightingStyle.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007-2013 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +package org.geometerplus.fbreader.book; + +import java.util.Map; +import java.util.HashMap; + +import org.geometerplus.zlibrary.core.util.ZLColor; + +public class HighlightingStyle { + public final int Id; + public final ZLColor BackgroundColor; + + HighlightingStyle(int id, ZLColor bgColor) { + Id = id; + BackgroundColor = bgColor; + } +} diff --git a/src/org/geometerplus/fbreader/book/IBookCollection.java b/src/org/geometerplus/fbreader/book/IBookCollection.java index 373f65d28..d13152308 100644 --- a/src/org/geometerplus/fbreader/book/IBookCollection.java +++ b/src/org/geometerplus/fbreader/book/IBookCollection.java @@ -82,4 +82,7 @@ public interface IBookCollection { List bookmarks(BookmarkQuery query); void saveBookmark(Bookmark bookmark); void deleteBookmark(Bookmark bookmark); + + HighlightingStyle getHighlightingStyle(int styleId); + List highlightingStyles(); } diff --git a/src/org/geometerplus/fbreader/book/SerializerUtil.java b/src/org/geometerplus/fbreader/book/SerializerUtil.java index d12f2791b..2175198af 100644 --- a/src/org/geometerplus/fbreader/book/SerializerUtil.java +++ b/src/org/geometerplus/fbreader/book/SerializerUtil.java @@ -51,14 +51,6 @@ public abstract class SerializerUtil { return xml != null ? defaultSerializer.deserializeBook(xml) : null; } - public static String serialize(Bookmark bookmark) { - return bookmark != null ? defaultSerializer.serialize(bookmark) : null; - } - - public static Bookmark deserializeBookmark(String xml) { - return xml != null ? defaultSerializer.deserializeBookmark(xml) : null; - } - public static List serializeBookList(List books) { final List serialized = new ArrayList(books.size()); for (Book b : books) { @@ -78,6 +70,14 @@ public abstract class SerializerUtil { return books; } + public static String serialize(Bookmark bookmark) { + return bookmark != null ? defaultSerializer.serialize(bookmark) : null; + } + + public static Bookmark deserializeBookmark(String xml) { + return xml != null ? defaultSerializer.deserializeBookmark(xml) : null; + } + public static List serializeBookmarkList(List bookmarks) { final List serialized = new ArrayList(bookmarks.size()); for (Bookmark b : bookmarks) { @@ -96,4 +96,31 @@ public abstract class SerializerUtil { } return bookmarks; } + + public static String serialize(HighlightingStyle style) { + return style != null ? defaultSerializer.serialize(style) : null; + } + + public static HighlightingStyle deserializeStyle(String xml) { + return xml != null ? defaultSerializer.deserializeStyle(xml) : null; + } + + public static List serializeStyleList(List styles) { + final List serialized = new ArrayList(styles.size()); + for (HighlightingStyle s : styles) { + serialized.add(defaultSerializer.serialize(s)); + } + return serialized; + } + + public static List deserializeStyleList(List xmlList) { + final List styles = new ArrayList(xmlList.size()); + for (String xml : xmlList) { + final HighlightingStyle s = defaultSerializer.deserializeStyle(xml); + if (s != null) { + styles.add(s); + } + } + return styles; + } } diff --git a/src/org/geometerplus/fbreader/book/XMLSerializer.java b/src/org/geometerplus/fbreader/book/XMLSerializer.java index 0e69547ef..f3e526227 100644 --- a/src/org/geometerplus/fbreader/book/XMLSerializer.java +++ b/src/org/geometerplus/fbreader/book/XMLSerializer.java @@ -25,6 +25,7 @@ import java.text.ParseException; import org.geometerplus.zlibrary.core.constants.XMLNamespaces; import org.geometerplus.zlibrary.core.filesystem.ZLFile; +import org.geometerplus.zlibrary.core.util.ZLColor; import org.geometerplus.zlibrary.text.view.ZLTextPosition; @@ -305,6 +306,32 @@ class XMLSerializer extends AbstractSerializer { } } + @Override + public String serialize(HighlightingStyle style) { + final StringBuilder buffer = new StringBuilder(); + appendTag(buffer, "style", false, + "id", String.valueOf(style.Id) + ); + appendTag(buffer, "bg-color", true, + "value", String.valueOf(style.BackgroundColor.getIntValue()) + ); + closeTag(buffer, "style"); + return buffer.toString(); + } + + @Override + public HighlightingStyle deserializeStyle(String xml) { + try { + final StyleDeserializer deserializer = new StyleDeserializer(); + Xml.parse(xml, deserializer); + return deserializer.getStyle(); + } catch (SAXException e) { + System.err.println(xml); + e.printStackTrace(); + return null; + } + } + private static DateFormat ourDateFormatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL, Locale.ENGLISH); private static String formatDate(Date date) { return date != null ? ourDateFormatter.format(date) : null; @@ -930,4 +957,45 @@ class XMLSerializer extends AbstractSerializer { } } } + + private static final class StyleDeserializer extends DefaultHandler { + private HighlightingStyle myStyle; + + private int myId = -1; + private int myColor; + + public HighlightingStyle getStyle() { + return myStyle; + } + + @Override + public void startDocument() { + myStyle = null; + myId = -1; + } + + @Override + public void endDocument() { + if (myId != -1) { + myStyle = new HighlightingStyle(myId, new ZLColor(myColor)); + } + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if ("style".equals(localName)) { + try { + myId = Integer.parseInt(attributes.getValue("id")); + } catch (Exception e) { + throw new SAXException("XML parsing error", e); + } + } else if ("bg-color".equals(localName)) { + try { + myColor = Integer.parseInt(attributes.getValue("value")); + } catch (Exception e) { + throw new SAXException("XML parsing error", e); + } + } + } + } } diff --git a/src/org/geometerplus/fbreader/fbreader/BookmarkHighlighting.java b/src/org/geometerplus/fbreader/fbreader/BookmarkHighlighting.java index 07d5dc6fc..fe8ee7e30 100644 --- a/src/org/geometerplus/fbreader/fbreader/BookmarkHighlighting.java +++ b/src/org/geometerplus/fbreader/fbreader/BookmarkHighlighting.java @@ -23,9 +23,12 @@ import org.geometerplus.zlibrary.core.util.ZLColor; import org.geometerplus.zlibrary.text.view.*; -import org.geometerplus.fbreader.book.Bookmark; +import org.geometerplus.fbreader.book.*; public final class BookmarkHighlighting extends ZLTextSimpleHighlighting { + final IBookCollection myCollection; + final Bookmark myBookmark; + private static ZLTextPosition endPosition(Bookmark bookmark) { final ZLTextPosition end = bookmark.getEnd(); if (end != null) { @@ -35,12 +38,15 @@ public final class BookmarkHighlighting extends ZLTextSimpleHighlighting { return bookmark; } - BookmarkHighlighting(ZLTextView view, Bookmark bookmark) { + BookmarkHighlighting(ZLTextView view, IBookCollection collection, Bookmark bookmark) { super(view, bookmark, endPosition(bookmark)); + myCollection = collection; + myBookmark = bookmark; } @Override public ZLColor getBackgroundColor() { - return new ZLColor(0x888A85); + final HighlightingStyle bmStyle = myCollection.getHighlightingStyle(myBookmark.getStyleId()); + return bmStyle != null ? bmStyle.BackgroundColor : new ZLColor(255, 255, 255); } } diff --git a/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java b/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java index 5444816b1..c6695e510 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java @@ -259,7 +259,7 @@ public final class FBReaderApp extends ZLApplication { } for (Bookmark b : bookmarks) { if (b.ModelId == null) { - BookTextView.addHighlighting(new BookmarkHighlighting(BookTextView, b)); + BookTextView.addHighlighting(new BookmarkHighlighting(BookTextView, Collection, b)); } } } diff --git a/src/org/geometerplus/zlibrary/core/util/ZLColor.java b/src/org/geometerplus/zlibrary/core/util/ZLColor.java index 7e4366b90..7d0b59355 100644 --- a/src/org/geometerplus/zlibrary/core/util/ZLColor.java +++ b/src/org/geometerplus/zlibrary/core/util/ZLColor.java @@ -44,6 +44,7 @@ public final class ZLColor { return (Red << 16) + (Green << 8) + Blue; } + @Override public boolean equals(Object o) { if (o == this) { return true; @@ -57,7 +58,17 @@ public final class ZLColor { return (color.Red == Red) && (color.Green == Green) && (color.Blue == Blue); } + @Override public int hashCode() { return getIntValue(); } + + @Override + public String toString() { + return new StringBuilder("ZLColor(") + .append(String.valueOf(Red)).append(", ") + .append(String.valueOf(Green)).append(", ") + .append(String.valueOf(Blue)).append(")") + .toString(); + } }