summaryrefslogtreecommitdiffstats
path: root/fbreader/src/libraryTree
diff options
context:
space:
mode:
Diffstat (limited to 'fbreader/src/libraryTree')
-rw-r--r--fbreader/src/libraryTree/AuthorNode.cpp60
-rw-r--r--fbreader/src/libraryTree/BookNode.cpp116
-rw-r--r--fbreader/src/libraryTree/LibraryByAuthorView.cpp173
-rw-r--r--fbreader/src/libraryTree/LibraryByTagView.cpp97
-rw-r--r--fbreader/src/libraryTree/LibraryNodes.h120
-rw-r--r--fbreader/src/libraryTree/LibraryView.cpp86
-rw-r--r--fbreader/src/libraryTree/LibraryView.h86
-rw-r--r--fbreader/src/libraryTree/SeriesNode.cpp61
-rw-r--r--fbreader/src/libraryTree/TagNode.cpp78
9 files changed, 877 insertions, 0 deletions
diff --git a/fbreader/src/libraryTree/AuthorNode.cpp b/fbreader/src/libraryTree/AuthorNode.cpp
new file mode 100644
index 0000000..a250c1a
--- /dev/null
+++ b/fbreader/src/libraryTree/AuthorNode.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include <ZLResource.h>
+#include <ZLImage.h>
+#include <ZLOptionsDialog.h>
+
+#include "LibraryNodes.h"
+
+#include "../library/Author.h"
+#include "../libraryActions/LibraryAuthorActions.h"
+
+const ZLTypeId AuthorNode::TYPE_ID(FBReaderNode::TYPE_ID);
+
+const ZLResource &AuthorNode::resource() const {
+ return ZLResource::resource("libraryView")["authorNode"];
+}
+
+const ZLTypeId &AuthorNode::typeId() const {
+ return TYPE_ID;
+}
+
+AuthorNode::AuthorNode(ZLBlockTreeView::RootNode *parent, std::size_t atPosition, shared_ptr<Author> author) : FBReaderNode(parent, atPosition), myAuthor(author) {
+}
+
+void AuthorNode::init() {
+ registerExpandTreeAction();
+ if (!myAuthor.isNull()) {
+ registerAction(new AuthorEditInfoAction(myAuthor));
+ }
+}
+
+shared_ptr<Author> AuthorNode::author() const {
+ return myAuthor;
+}
+
+std::string AuthorNode::title() const {
+ return myAuthor.isNull() ?
+ resource()["unknownAuthor"].value() : myAuthor->name();
+}
+
+shared_ptr<const ZLImage> AuthorNode::extractCoverImage() const {
+ return defaultCoverImage("booktree-author.png");
+}
diff --git a/fbreader/src/libraryTree/BookNode.cpp b/fbreader/src/libraryTree/BookNode.cpp
new file mode 100644
index 0000000..0df43e5
--- /dev/null
+++ b/fbreader/src/libraryTree/BookNode.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include <ZLResource.h>
+#include <ZLImage.h>
+
+#include "LibraryNodes.h"
+
+#include "../library/Book.h"
+#include "../library/Author.h"
+#include "../library/Tag.h"
+#include "../libraryActions/LibraryBookActions.h"
+
+#include "../fbreader/FBReader.h"
+#include "../formats/FormatPlugin.h"
+
+const ZLTypeId BookNode::TYPE_ID(FBReaderNode::TYPE_ID);
+
+const ZLTypeId &BookNode::typeId() const {
+ return TYPE_ID;
+}
+
+const ZLResource &BookNode::resource() const {
+ return ZLResource::resource("libraryView")["bookNode"];
+}
+
+BookNode::BookNode(AuthorNode *parent, shared_ptr<Book> book) : FBReaderNode(parent), myBook(book) {
+}
+
+BookNode::BookNode(SeriesNode *parent, shared_ptr<Book> book) : FBReaderNode(parent), myBook(book) {
+}
+
+BookNode::BookNode(TagNode *parent, std::size_t atPosition, shared_ptr<Book> book) : FBReaderNode(parent, atPosition), myBook(book) {
+}
+
+void BookNode::init() {
+ registerAction(new BookReadAction(myBook));
+ registerAction(new BookEditInfoAction(myBook));
+ registerAction(new BookRemoveAction(myBook));
+}
+
+shared_ptr<Book> BookNode::book() const {
+ return myBook;
+}
+
+std::string BookNode::title() const {
+ return myBook->title();
+}
+
+std::string BookNode::summary() const {
+ FBReaderNode *parent = (FBReaderNode*)this->parent();
+ while (!parent->isInstanceOf(AuthorNode::TYPE_ID) &&
+ !parent->isInstanceOf(TagNode::TYPE_ID)) {
+ parent = (FBReaderNode*)parent->parent();
+ }
+ if (parent->isInstanceOf(AuthorNode::TYPE_ID)) {
+ const TagList &tags = myBook->tags();
+ if (tags.empty()) {
+ return std::string();
+ } else {
+ std::string tagsText;
+ for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) {
+ if (!tagsText.empty()) {
+ tagsText += ", ";
+ }
+ tagsText += (*it)->name();
+ }
+ return tagsText;
+ }
+ } else {
+ const AuthorList &authors = myBook->authors();
+ if (authors.empty()) {
+ return ZLResource::resource("libraryView")["authorNode"]["unknownAuthor"].value();
+ } else {
+ std::string authorsText;
+ for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) {
+ if (!authorsText.empty()) {
+ authorsText += ", ";
+ }
+ authorsText += (*it)->name();
+ }
+ return authorsText;
+ }
+ }
+}
+
+bool BookNode::highlighted() const {
+ return myBook->file() == FBReader::Instance().currentBook()->file();
+}
+
+shared_ptr<const ZLImage> BookNode::extractCoverImage() const {
+ shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(*myBook);
+ if (!plugin.isNull()) {
+ shared_ptr<const ZLImage> cover = plugin->coverImage(myBook->file());
+ if (!cover.isNull()) {
+ return cover;
+ }
+ }
+ return defaultCoverImage("booktree-book.png");
+}
diff --git a/fbreader/src/libraryTree/LibraryByAuthorView.cpp b/fbreader/src/libraryTree/LibraryByAuthorView.cpp
new file mode 100644
index 0000000..68a13f4
--- /dev/null
+++ b/fbreader/src/libraryTree/LibraryByAuthorView.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include "LibraryView.h"
+#include "LibraryNodes.h"
+
+#include "../library/Library.h"
+#include "../library/Book.h"
+#include "../library/Author.h"
+
+LibraryByAuthorView::LibraryByAuthorView(ZLPaintContext &context) : LibraryView(context) {
+}
+
+void LibraryByAuthorView::addAuthorSubtree(shared_ptr<Author> author, std::size_t atPosition) {
+ static const std::set<shared_ptr<Book> > emptySet;
+ fillAuthorSubtree(new AuthorNode(&rootNode(), atPosition, author), emptySet);
+}
+
+void LibraryByAuthorView::fillAuthorSubtree(AuthorNode *authorNode, const std::set<shared_ptr<Book> > &visibleBooks) {
+ const BookList &books = Library::Instance().books(authorNode->author());
+ SeriesNode *seriesNode = 0;
+ for (BookList::const_iterator it = books.begin(); it != books.end(); ++it) {
+ std::string series = (*it)->seriesTitle();
+
+ if (!series.empty() && (seriesNode == 0 || seriesNode->book()->seriesTitle() != series)) {
+ BookList::const_iterator jt = it + 1;
+ if (jt == books.end() || (*jt)->seriesTitle() != series) {
+ series.clear();
+ }
+ }
+
+ if (series.empty()) {
+ seriesNode = 0;
+ new BookNode(authorNode, *it);
+ } else {
+ if (seriesNode == 0 || seriesNode->book()->seriesTitle() != series) {
+ seriesNode = new SeriesNode(authorNode);
+ }
+ new BookNode(seriesNode, *it);
+ if (visibleBooks.find(*it) != visibleBooks.end()) {
+ seriesNode->open(true);
+ }
+ }
+ }
+}
+
+bool LibraryByAuthorView::isSubtreeUpToDate(AuthorNode *authorNode) {
+ const BookList &books = Library::Instance().books(authorNode->author());
+ BookList::const_iterator it = books.begin();
+
+ const ZLBlockTreeNode::List &nodes = authorNode->children();
+ for (ZLBlockTreeNode::List::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt) {
+ FBReaderNode &node = *(FBReaderNode*)*nIt;
+ if (node.isInstanceOf(BookNode::TYPE_ID)) {
+ shared_ptr<Book> book = ((BookNode&)node).book();
+ if (it == books.end() || *it != book || !book->seriesTitle().empty()) {
+ return false;
+ }
+ ++it;
+ } else /* if (node.isInstanceOf(SeriesNode::TYPE_ID)) */ {
+ const ZLBlockTreeNode::List &bNodes = node.children();
+ for (ZLBlockTreeNode::List::const_iterator bookIt = bNodes.begin(); bookIt != bNodes.end(); ++bookIt) {
+ shared_ptr<Book> book = ((BookNode*)*bookIt)->book();
+ if (it == books.end() || *it != book || book->seriesTitle().empty()) {
+ return false;
+ }
+ ++it;
+ }
+ }
+ }
+ return it == books.end();
+}
+
+void LibraryByAuthorView::updateAuthorSubtree(AuthorNode *authorNode) {
+ std::set<shared_ptr<Book> > visibleBooks;
+
+ const ZLBlockTreeNode::List &nodes = authorNode->children();
+ for (ZLBlockTreeNode::List::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt) {
+ FBReaderNode &node = *(FBReaderNode*)*nIt;
+ if (node.isInstanceOf(BookNode::TYPE_ID)) {
+ visibleBooks.insert(((BookNode&)node).book());
+ } else if (node.isOpen()) {
+ const ZLBlockTreeNode::List &bNodes = node.children();
+ for (ZLBlockTreeNode::List::const_iterator bookIt = bNodes.begin(); bookIt != bNodes.end(); ++bookIt) {
+ visibleBooks.insert(((BookNode*)*bookIt)->book());
+ }
+ }
+ }
+
+ authorNode->clear();
+ fillAuthorSubtree(authorNode, visibleBooks);
+}
+
+void LibraryByAuthorView::makeUpToDate() {
+ ZLBlockTreeNode *topNode = firstVisibleNode();
+ AuthorNode *topAuthorNode = 0;
+ if (topNode != &rootNode()) {
+ FBReaderNode *lNode = (FBReaderNode*)topNode;
+ while (!lNode->isInstanceOf(AuthorNode::TYPE_ID)) {
+ lNode = (FBReaderNode*)lNode->parent();
+ }
+ topAuthorNode = (AuthorNode*)lNode;
+ }
+
+ bool topAuthorNodeIsUpdated = false;
+ const AuthorList &authors = Library::Instance().authors();
+ std::set<ZLBlockTreeNode*> nodesToDelete;
+ ZLBlockTreeNode::List rootChildren = rootNode().children();
+ AuthorComparator comparator;
+
+ ZLBlockTreeNode::List::iterator nodeIt = rootChildren.begin();
+ std::size_t nodeCount = 0;
+ for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) {
+ bool processed = false;
+ while (nodeIt != rootChildren.end()) {
+ AuthorNode *authorNode = (AuthorNode*)*nodeIt;
+ if (authorNode->author() == *it) {
+ if (!isSubtreeUpToDate(authorNode)) {
+ updateAuthorSubtree(authorNode);
+ if (authorNode == topAuthorNode) {
+ topAuthorNodeIsUpdated = true;
+ }
+ }
+ ++nodeIt;
+ ++nodeCount;
+ processed = true;
+ break;
+ } else if (comparator(authorNode->author(), *it)) {
+ nodesToDelete.insert(*nodeIt);
+ ++nodeIt;
+ ++nodeCount;
+ } else {
+ break;
+ }
+ }
+ if (!processed) {
+ addAuthorSubtree(*it, nodeCount);
+ ++nodeCount;
+ }
+ }
+
+ nodesToDelete.insert(nodeIt, rootChildren.end());
+
+ if (topAuthorNodeIsUpdated) {
+ setFirstVisibleNode(topAuthorNode);
+ } else if (nodesToDelete.find(topAuthorNode) != nodesToDelete.end()) {
+ ZLBlockTreeNode *visible = topAuthorNode->previous();
+ while (nodesToDelete.find(visible) != nodesToDelete.end()) {
+ visible = visible->previous();
+ }
+ setFirstVisibleNode(visible);
+ }
+
+ for (std::set<ZLBlockTreeNode*>::iterator it = nodesToDelete.begin(); it != nodesToDelete.end(); ++it) {
+ delete *it;
+ }
+}
diff --git a/fbreader/src/libraryTree/LibraryByTagView.cpp b/fbreader/src/libraryTree/LibraryByTagView.cpp
new file mode 100644
index 0000000..76913f1
--- /dev/null
+++ b/fbreader/src/libraryTree/LibraryByTagView.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include "LibraryView.h"
+#include "LibraryNodes.h"
+
+#include "../library/Library.h"
+#include "../library/Book.h"
+#include "../library/Tag.h"
+#include "../libraryActions/BooksUtil.h"
+
+LibraryByTagView::LibraryByTagView(ZLPaintContext &context) : LibraryView(context) {
+}
+
+void LibraryByTagView::collectTagNodes(const ZLBlockTreeNode &root, std::map<shared_ptr<Tag>,TagNode*,TagComparator> &nodeMap) {
+ const ZLBlockTreeNode::List &children = root.children();
+ for (ZLBlockTreeNode::List::const_iterator it = children.begin(); it != children.end(); ++it) {
+ if ((*it)->isInstanceOf(TagNode::TYPE_ID)) {
+ TagNode *tagNode = (TagNode*)*it;
+ nodeMap[tagNode->tag()] = tagNode;
+ collectTagNodes(*tagNode, nodeMap);
+ }
+ }
+}
+
+void LibraryByTagView::updateBookList(TagNode *tagNode) {
+ const BookList &books = Library::Instance().books(tagNode->tag());
+ const ZLBlockTreeNode::List &subNodes = tagNode->children();
+ BookList::const_iterator jt = books.begin();
+ ZLBlockTreeNode::List::const_iterator kt = subNodes.begin();
+ for (; jt != books.end() && kt != subNodes.end(); ++jt, ++kt) {
+ if (!(*kt)->isInstanceOf(BookNode::TYPE_ID)) {
+ break;
+ }
+ if (((BookNode*)(*kt))->book()->file() != (*jt)->file()) {
+ break;
+ }
+ }
+
+ std::size_t index = jt - books.begin();
+ while (tagNode->children().size() > index) {
+ ZLBlockTreeNode *bookNode = tagNode->children()[index];
+ if (!bookNode->isInstanceOf(BookNode::TYPE_ID)) {
+ break;
+ }
+ delete bookNode;
+ }
+
+ for (; jt != books.end(); ++jt) {
+ new BookNode(tagNode, index++, *jt);
+ }
+}
+
+void LibraryByTagView::makeUpToDate() {
+ TagList tags;
+ BooksUtil::collectTagsFromLibrary(tags);
+
+ std::map<shared_ptr<Tag>,TagNode*,TagComparator> nodeMap;
+ collectTagNodes(rootNode(), nodeMap);
+
+ for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) {
+ shared_ptr<Tag> tag = *it;
+ TagNode *tagNode = nodeMap[tag];
+ if (tagNode == 0) {
+ tagNode =
+ (tag.isNull() || tag->parent().isNull()) ?
+ new TagNode(&rootNode(), tag) :
+ new TagNode(nodeMap[tag->parent()], tag);
+ nodeMap[tag] = tagNode;
+ }
+ updateBookList(tagNode);
+ }
+
+ for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) {
+ nodeMap.erase(nodeMap.find(*it));
+ }
+
+ for (std::map<shared_ptr<Tag>,TagNode*,TagComparator>::reverse_iterator it = nodeMap.rbegin(); it != nodeMap.rend(); ++it) {
+ delete it->second;
+ }
+}
diff --git a/fbreader/src/libraryTree/LibraryNodes.h b/fbreader/src/libraryTree/LibraryNodes.h
new file mode 100644
index 0000000..5f1eab9
--- /dev/null
+++ b/fbreader/src/libraryTree/LibraryNodes.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __LIBRARYNODES_H__
+#define __LIBRARYNODES_H__
+
+#include "../blockTree/FBReaderNode.h"
+
+class ZLImage;
+
+class Author;
+class Book;
+class Tag;
+
+class AuthorNode : public FBReaderNode {
+
+public:
+ static const ZLTypeId TYPE_ID;
+
+public:
+ AuthorNode(ZLBlockTreeView::RootNode *parent, std::size_t atPosition, shared_ptr<Author> author);
+ void init();
+
+ shared_ptr<Author> author() const;
+
+private:
+ const ZLResource &resource() const;
+ const ZLTypeId &typeId() const;
+ shared_ptr<const ZLImage> extractCoverImage() const;
+ std::string title() const;
+
+private:
+ shared_ptr<Author> myAuthor;
+};
+
+class SeriesNode : public FBReaderNode {
+
+public:
+ static const ZLTypeId TYPE_ID;
+
+public:
+ SeriesNode(AuthorNode *parent);
+ void init();
+
+ shared_ptr<Book> book() const;
+
+private:
+ const ZLResource &resource() const;
+ const ZLTypeId &typeId() const;
+ shared_ptr<const ZLImage> extractCoverImage() const;
+ std::string title() const;
+};
+
+class TagNode : public FBReaderNode {
+
+public:
+ static const ZLTypeId TYPE_ID;
+
+private:
+ static std::size_t positionToInsert(ZLBlockTreeNode *parent, shared_ptr<Tag> tag);
+
+public:
+ TagNode(ZLBlockTreeView::RootNode *parent, shared_ptr<Tag> tag);
+ TagNode(TagNode *parent, shared_ptr<Tag> tag);
+ void init();
+
+ shared_ptr<Tag> tag() const;
+
+private:
+ const ZLResource &resource() const;
+ const ZLTypeId &typeId() const;
+ shared_ptr<const ZLImage> extractCoverImage() const;
+ std::string title() const;
+
+private:
+ const shared_ptr<Tag> myTag;
+};
+
+class BookNode : public FBReaderNode {
+
+public:
+ static const ZLTypeId TYPE_ID;
+
+public:
+ BookNode(AuthorNode *parent, shared_ptr<Book> book);
+ BookNode(SeriesNode *parent, shared_ptr<Book> book);
+ BookNode(TagNode *parent, std::size_t atPosition, shared_ptr<Book> book);
+
+ shared_ptr<Book> book() const;
+
+private:
+ void init();
+ bool highlighted() const;
+ const ZLResource &resource() const;
+ const ZLTypeId &typeId() const;
+ shared_ptr<const ZLImage> extractCoverImage() const;
+ std::string title() const;
+ std::string summary() const;
+
+private:
+ const shared_ptr<Book> myBook;
+};
+
+#endif /* __LIBRARYNODES_H__ */
diff --git a/fbreader/src/libraryTree/LibraryView.cpp b/fbreader/src/libraryTree/LibraryView.cpp
new file mode 100644
index 0000000..067c865
--- /dev/null
+++ b/fbreader/src/libraryTree/LibraryView.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include <queue>
+
+#include <ZLResource.h>
+
+#include "LibraryView.h"
+#include "LibraryNodes.h"
+
+#include "../library/Library.h"
+#include "../library/Book.h"
+#include "../options/FBOptions.h"
+
+LibraryView::LibraryView(ZLPaintContext &context) : ZLBlockTreeView(context), myCollectionRevision(0) {
+}
+
+void LibraryView::paint() {
+ const std::size_t revision = Library::Instance().revision();
+ if (myCollectionRevision < revision) {
+ myCollectionRevision = revision;
+ makeUpToDate();
+ }
+
+ ZLBlockTreeView::paint();
+}
+
+const std::string &LibraryView::caption() const {
+ return ZLResource::resource("library")["caption"].value();
+}
+
+ZLColor LibraryView::backgroundColor() const {
+ return FBOptions::Instance().BackgroundColorOption.value();
+}
+
+void LibraryView::showBook(shared_ptr<Book> book) {
+ makeUpToDate();
+ ZLBlockTreeNode::List bookNodes;
+ std::queue<ZLBlockTreeNode*> nodesQueue;
+ nodesQueue.push(&rootNode());
+ while (!nodesQueue.empty()) {
+ const ZLBlockTreeNode::List &children = nodesQueue.front()->children();
+ nodesQueue.pop();
+ for (ZLBlockTreeNode::List::const_iterator it = children.begin(); it != children.end(); ++it) {
+ if ((*it)->isInstanceOf(BookNode::TYPE_ID)) {
+ // TODO: replace with == for shared_ptr<Book>
+ //if (((BookNode*)*it)->book() == book) {
+ if (((BookNode*)*it)->book()->file() == book->file()) {
+ bookNodes.push_back(*it);
+ }
+ } else {
+ nodesQueue.push(*it);
+ }
+ }
+ }
+ if (bookNodes.empty()) {
+ return;
+ }
+ ZLBlockTreeNode *nodeToShow = bookNodes[0];
+ VisibilityMode mode = INVISIBLE;
+ for (ZLBlockTreeNode::List::iterator it = bookNodes.begin(); it != bookNodes.end(); ++it) {
+ VisibilityMode nodeMode = visibilityMode(*it);
+ if ((nodeMode == VISIBLE && mode != VISIBLE) ||
+ (nodeMode != INVISIBLE && mode == INVISIBLE)) {
+ nodeToShow = *it;
+ mode = nodeMode;
+ }
+ }
+ ensureVisible(nodeToShow);
+}
diff --git a/fbreader/src/libraryTree/LibraryView.h b/fbreader/src/libraryTree/LibraryView.h
new file mode 100644
index 0000000..40715f6
--- /dev/null
+++ b/fbreader/src/libraryTree/LibraryView.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __LIBRARYVIEW_H__
+#define __LIBRARYVIEW_H__
+
+#include <map>
+#include <set>
+
+#include <ZLBlockTreeView.h>
+
+#include "../library/Lists.h"
+
+class Book;
+class Author;
+class Tag;
+class TagComparator;
+
+class AuthorNode;
+class TagNode;
+
+class LibraryView : public ZLBlockTreeView {
+
+protected:
+ LibraryView(ZLPaintContext &context);
+
+public:
+ void showBook(shared_ptr<Book>);
+
+private:
+ ZLColor backgroundColor() const;
+ const std::string &caption() const;
+
+private:
+ void paint();
+
+protected:
+ virtual void makeUpToDate() = 0;
+
+private:
+ std::size_t myCollectionRevision;
+};
+
+class LibraryByAuthorView : public LibraryView {
+
+public:
+ LibraryByAuthorView(ZLPaintContext &context);
+
+private:
+ void makeUpToDate();
+
+ void addAuthorSubtree(shared_ptr<Author> author, std::size_t atPosition);
+ void fillAuthorSubtree(AuthorNode *node, const std::set<shared_ptr<Book> > &visibleBooks);
+ bool isSubtreeUpToDate(AuthorNode *node);
+ void updateAuthorSubtree(AuthorNode *node);
+};
+
+class LibraryByTagView : public LibraryView {
+
+public:
+ LibraryByTagView(ZLPaintContext &context);
+
+private:
+ void makeUpToDate();
+
+ void collectTagNodes(const ZLBlockTreeNode &root, std::map<shared_ptr<Tag>,TagNode*,TagComparator> &nodeMap);
+ void updateBookList(TagNode *tagNode);
+};
+
+#endif /* __LIBRARYVIEW_H__ */
diff --git a/fbreader/src/libraryTree/SeriesNode.cpp b/fbreader/src/libraryTree/SeriesNode.cpp
new file mode 100644
index 0000000..6d4aafa
--- /dev/null
+++ b/fbreader/src/libraryTree/SeriesNode.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include <ZLImage.h>
+#include <ZLResource.h>
+
+#include "LibraryNodes.h"
+
+#include "../library/Book.h"
+
+const ZLTypeId SeriesNode::TYPE_ID(FBReaderNode::TYPE_ID);
+
+const ZLResource &SeriesNode::resource() const {
+ return ZLResource::resource("libraryView")["seriesNode"];
+}
+
+const ZLTypeId &SeriesNode::typeId() const {
+ return TYPE_ID;
+}
+
+SeriesNode::SeriesNode(AuthorNode *parent) : FBReaderNode(parent) {
+}
+
+void SeriesNode::init() {
+ registerExpandTreeAction();
+}
+
+shared_ptr<Book> SeriesNode::book() const {
+ return ((BookNode&)*children().front()).book();
+}
+
+std::string SeriesNode::title() const {
+ return book()->seriesTitle();
+}
+
+shared_ptr<const ZLImage> SeriesNode::extractCoverImage() const {
+ const std::vector<ZLBlockTreeNode*> &books = children();
+ for (std::vector<ZLBlockTreeNode*>::const_iterator it = books.begin(); it != books.end(); ++it) {
+ shared_ptr<const ZLImage> bookCover = ((FBReaderNode*)*it)->coverImage();
+ if (!bookCover.isNull()) {
+ return bookCover;
+ }
+ }
+ return 0;
+}
diff --git a/fbreader/src/libraryTree/TagNode.cpp b/fbreader/src/libraryTree/TagNode.cpp
new file mode 100644
index 0000000..7ccd3ac
--- /dev/null
+++ b/fbreader/src/libraryTree/TagNode.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009-2012 Geometer Plus <[email protected]>
+ *
+ * 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.
+ */
+
+#include <ZLResource.h>
+#include <ZLImage.h>
+
+#include "LibraryNodes.h"
+
+#include "../library/Tag.h"
+#include "../libraryActions/LibraryTagActions.h"
+
+const ZLTypeId TagNode::TYPE_ID(FBReaderNode::TYPE_ID);
+
+const ZLTypeId &TagNode::typeId() const {
+ return TYPE_ID;
+}
+
+const ZLResource &TagNode::resource() const {
+ return ZLResource::resource("libraryView")["tagNode"];
+}
+
+std::size_t TagNode::positionToInsert(ZLBlockTreeNode *parent, shared_ptr<Tag> tag) {
+ const ZLBlockTreeNode::List &children = parent->children();
+ ZLBlockTreeNode::List::const_reverse_iterator it = children.rbegin();
+ for (; it != children.rend(); ++it) {
+ if (!(*it)->isInstanceOf(TagNode::TYPE_ID) ||
+ TagComparator()(((TagNode*)*it)->tag(), tag)) {
+ break;
+ }
+ }
+ return children.rend() - it;
+}
+
+TagNode::TagNode(ZLBlockTreeView::RootNode *parent, shared_ptr<Tag> tag) : FBReaderNode(parent, positionToInsert(parent, tag)), myTag(tag) {
+}
+
+TagNode::TagNode(TagNode *parent, shared_ptr<Tag> tag) : FBReaderNode(parent, positionToInsert(parent, tag)), myTag(tag) {
+}
+
+void TagNode::init() {
+ registerExpandTreeAction();
+ if (!myTag.isNull()) {
+ registerAction(new TagEditAction(myTag));
+ registerAction(new TagCloneAction(myTag));
+ registerAction(new TagRemoveAction(myTag));
+ }
+}
+
+shared_ptr<Tag> TagNode::tag() const {
+ return myTag;
+}
+
+std::string TagNode::title() const {
+ if (myTag.isNull()) {
+ return resource()["noTags"].value();
+ }
+ return myTag->name();
+}
+
+shared_ptr<const ZLImage> TagNode::extractCoverImage() const {
+ return defaultCoverImage("booktree-tag.png");
+}